aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Module.zig8
-rw-r--r--src/Sema.zig184
-rw-r--r--src/codegen.zig2
-rw-r--r--src/codegen/c.zig3
-rw-r--r--src/codegen/llvm.zig103
-rw-r--r--src/link/Coff.zig29
-rw-r--r--src/link/MachO.zig5
-rw-r--r--src/link/MachO/Object.zig16
-rw-r--r--src/link/Wasm.zig13
-rw-r--r--src/link/Wasm/Archive.zig121
-rw-r--r--src/link/Wasm/Object.zig23
-rw-r--r--src/type.zig11
-rw-r--r--src/zig_llvm.cpp2
13 files changed, 386 insertions, 134 deletions
diff --git a/src/Module.zig b/src/Module.zig
index 3577115ded..45e0779c54 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -6072,17 +6072,17 @@ pub fn paramSrc(
else => unreachable,
};
var it = full.iterate(tree);
- while (true) {
- if (it.param_i == param_i) {
- const param = it.next().?;
+ var i: usize = 0;
+ while (it.next()) |param| : (i += 1) {
+ if (i == param_i) {
if (param.anytype_ellipsis3) |some| {
const main_token = tree.nodes.items(.main_token)[decl.src_node];
return .{ .token_offset_param = @bitCast(i32, some) - @bitCast(i32, main_token) };
}
return .{ .node_offset_param = decl.nodeIndexToRelative(param.type_expr) };
}
- _ = it.next();
}
+ unreachable;
}
pub fn argSrc(
diff --git a/src/Sema.zig b/src/Sema.zig
index aa02288df7..4f558ccae4 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -76,6 +76,8 @@ types_to_resolve: std.ArrayListUnmanaged(Air.Inst.Ref) = .{},
post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .{},
/// Populated with the last compile error created.
err: ?*Module.ErrorMsg = null,
+/// True when analyzing a generic instantiation. Used to suppress some errors.
+is_generic_instantiation: bool = false,
const std = @import("std");
const math = std.math;
@@ -1696,7 +1698,10 @@ fn resolveMaybeUndefValIntable(
.elem_ptr => check = check.castTag(.elem_ptr).?.data.array_ptr,
.eu_payload_ptr, .opt_payload_ptr => check = check.cast(Value.Payload.PayloadPtr).?.data.container_ptr,
.generic_poison => return error.GenericPoison,
- else => return val,
+ else => {
+ try sema.resolveLazyValue(block, src, val);
+ return val;
+ },
};
}
@@ -3087,7 +3092,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
const candidate = block.instructions.items[search_index];
switch (air_tags[candidate]) {
- .dbg_stmt => continue,
+ .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
.store => break candidate,
else => break :ct,
}
@@ -3099,7 +3104,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
const candidate = block.instructions.items[search_index];
switch (air_tags[candidate]) {
- .dbg_stmt => continue,
+ .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
.alloc => {
if (Air.indexToRef(candidate) != alloc) break :ct;
break;
@@ -3317,7 +3322,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
const candidate = block.instructions.items[search_index];
switch (air_tags[candidate]) {
- .dbg_stmt => continue,
+ .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
.store => break candidate,
else => break :ct,
}
@@ -3329,7 +3334,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
const candidate = block.instructions.items[search_index];
switch (air_tags[candidate]) {
- .dbg_stmt => continue,
+ .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
.bitcast => break candidate,
else => break :ct,
}
@@ -3341,7 +3346,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
const candidate = block.instructions.items[search_index];
switch (air_tags[candidate]) {
- .dbg_stmt => continue,
+ .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
.constant => break candidate,
else => break :ct,
}
@@ -3615,8 +3620,6 @@ fn validateUnionInit(
union_ptr: Air.Inst.Ref,
is_comptime: bool,
) CompileError!void {
- const union_obj = union_ty.cast(Type.Payload.Union).?.data;
-
if (instrs.len != 1) {
const msg = msg: {
const msg = try sema.errMsg(
@@ -3650,7 +3653,8 @@ fn validateUnionInit(
const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node };
const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start);
- const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src);
+ // Validate the field access but ignore the index since we want the tag enum field index.
+ _ = try sema.unionFieldIndex(block, union_ty, field_name, field_src);
const air_tags = sema.air_instructions.items(.tag);
const air_datas = sema.air_instructions.items(.data);
const field_ptr_air_ref = sema.inst_map.get(field_ptr).?;
@@ -3709,7 +3713,9 @@ fn validateUnionInit(
break;
}
- const tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);
+ const tag_ty = union_ty.unionTagTypeHypothetical();
+ const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
+ const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
if (init_val) |val| {
// Our task is to delete all the `field_ptr` and `store` instructions, and insert
@@ -3726,7 +3732,7 @@ fn validateUnionInit(
}
try sema.requireFunctionBlock(block, init_src);
- const new_tag = try sema.addConstant(union_obj.tag_ty, tag_val);
+ const new_tag = try sema.addConstant(tag_ty, tag_val);
_ = try block.addBinOp(.set_union_tag, union_ptr, new_tag);
}
@@ -5643,6 +5649,37 @@ const GenericCallAdapter = struct {
}
};
+fn addComptimeReturnTypeNote(
+ sema: *Sema,
+ block: *Block,
+ func: Air.Inst.Ref,
+ func_src: LazySrcLoc,
+ return_ty: Type,
+ parent: *Module.ErrorMsg,
+ requires_comptime: bool,
+) !void {
+ if (!requires_comptime) return;
+
+ const src_loc = if (try sema.funcDeclSrc(block, func_src, func)) |capture| blk: {
+ var src_loc = capture;
+ src_loc.lazy = .{ .node_offset_fn_type_ret_ty = 0 };
+ break :blk src_loc;
+ } else blk: {
+ const src_decl = sema.mod.declPtr(block.src_decl);
+ break :blk func_src.toSrcLoc(src_decl);
+ };
+ if (return_ty.tag() == .generic_poison) {
+ return sema.mod.errNoteNonLazy(src_loc, parent, "generic function is instantiated with a comptime only return type", .{});
+ }
+ try sema.mod.errNoteNonLazy(
+ src_loc,
+ parent,
+ "function is being called at comptime because it returns a comptime only type '{}'",
+ .{return_ty.fmt(sema.mod)},
+ );
+ try sema.explainWhyTypeIsComptime(block, func_src, parent, src_loc, return_ty);
+}
+
fn analyzeCall(
sema: *Sema,
block: *Block,
@@ -5733,9 +5770,11 @@ fn analyzeCall(
var is_generic_call = func_ty_info.is_generic;
var is_comptime_call = block.is_comptime or modifier == .compile_time;
+ var comptime_only_ret_ty = false;
if (!is_comptime_call) {
if (sema.typeRequiresComptime(block, func_src, func_ty_info.return_type)) |ct| {
is_comptime_call = ct;
+ comptime_only_ret_ty = ct;
} else |err| switch (err) {
error.GenericPoison => is_generic_call = true,
else => |e| return e,
@@ -5764,6 +5803,7 @@ fn analyzeCall(
error.ComptimeReturn => {
is_inline_call = true;
is_comptime_call = true;
+ comptime_only_ret_ty = true;
},
else => |e| return e,
}
@@ -5774,8 +5814,12 @@ fn analyzeCall(
}
const result: Air.Inst.Ref = if (is_inline_call) res: {
- // TODO explain why function is being called at comptime
- const func_val = try sema.resolveConstValue(block, func_src, func, "function being called at comptime must be comptime known");
+ const func_val = sema.resolveConstValue(block, func_src, func, "function being called at comptime must be comptime known") catch |err| {
+ if (err == error.AnalysisFail and sema.err != null) {
+ try sema.addComptimeReturnTypeNote(block, func, func_src, func_ty_info.return_type, sema.err.?, comptime_only_ret_ty);
+ }
+ return err;
+ };
const module_fn = switch (func_val.tag()) {
.decl_ref => mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data,
.function => func_val.castTag(.function).?.data,
@@ -5887,6 +5931,11 @@ fn analyzeCall(
is_comptime_call,
&should_memoize,
memoized_call_key,
+ // last 4 arguments are only used when reporting errors
+ undefined,
+ undefined,
+ undefined,
+ undefined,
) catch |err| switch (err) {
error.NeededSourceLocation => {
sema.inst_map.clearRetainingCapacity();
@@ -5904,6 +5953,10 @@ fn analyzeCall(
is_comptime_call,
&should_memoize,
memoized_call_key,
+ func,
+ func_src,
+ func_ty_info.return_type,
+ comptime_only_ret_ty,
);
return error.AnalysisFail;
},
@@ -6119,6 +6172,10 @@ fn analyzeInlineCallArg(
is_comptime_call: bool,
should_memoize: *bool,
memoized_call_key: Module.MemoizedCall.Key,
+ func: Air.Inst.Ref,
+ func_src: LazySrcLoc,
+ ret_ty: Type,
+ comptime_only_ret_ty: bool,
) !void {
const zir_tags = sema.code.instructions.items(.tag);
switch (zir_tags[inst]) {
@@ -6134,14 +6191,23 @@ fn analyzeInlineCallArg(
new_fn_info.param_types[arg_i.*] = param_ty;
const uncasted_arg = uncasted_args[arg_i.*];
if (try sema.typeRequiresComptime(arg_block, arg_src, param_ty)) {
- _ = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to parameter with comptime only type must be comptime known");
+ _ = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to parameter with comptime only type must be comptime known") catch |err| {
+ if (err == error.AnalysisFail and sema.err != null) {
+ try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty);
+ }
+ return err;
+ };
}
const casted_arg = try sema.coerce(arg_block, param_ty, uncasted_arg, arg_src);
try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg);
if (is_comptime_call) {
- // TODO explain why function is being called at comptime
- const arg_val = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "argument to function being called at comptime must be comptime known");
+ const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "argument to function being called at comptime must be comptime known") catch |err| {
+ if (err == error.AnalysisFail and sema.err != null) {
+ try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty);
+ }
+ return err;
+ };
switch (arg_val.tag()) {
.generic_poison, .generic_poison_type => {
// This function is currently evaluated as part of an as-of-yet unresolvable
@@ -6171,8 +6237,12 @@ fn analyzeInlineCallArg(
try sema.inst_map.putNoClobber(sema.gpa, inst, uncasted_arg);
if (is_comptime_call) {
- // TODO explain why function is being called at comptime
- const arg_val = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to function being called at comptime must be comptime known");
+ const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to function being called at comptime must be comptime known") catch |err| {
+ if (err == error.AnalysisFail and sema.err != null) {
+ try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty);
+ }
+ return err;
+ };
switch (arg_val.tag()) {
.generic_poison, .generic_poison_type => {
// This function is currently evaluated as part of an as-of-yet unresolvable
@@ -6430,6 +6500,7 @@ fn instantiateGenericCall(
.comptime_args = try new_decl_arena_allocator.alloc(TypedValue, uncasted_args.len),
.comptime_args_fn_inst = module_fn.zir_body_inst,
.preallocated_new_func = new_module_func,
+ .is_generic_instantiation = true,
};
defer child_sema.deinit();
@@ -7190,6 +7261,8 @@ fn zirOptionalPayload(
if (operand_ty.ptrSize() != .C) {
return sema.failWithExpectedOptionalType(block, src, operand_ty);
}
+ // TODO https://github.com/ziglang/zig/issues/6597
+ if (true) break :t operand_ty;
const ptr_info = operand_ty.ptrInfo().data;
break :t try Type.ptr(sema.arena, sema.mod, .{
.pointee_type = try ptr_info.pointee_type.copy(sema.arena),
@@ -7724,6 +7797,7 @@ fn funcCommon(
&is_generic,
is_extern,
cc_workaround,
+ has_body,
) catch |err| switch (err) {
error.NeededSourceLocation => {
const decl = sema.mod.declPtr(block.src_decl);
@@ -7737,6 +7811,7 @@ fn funcCommon(
&is_generic,
is_extern,
cc_workaround,
+ has_body,
);
return error.AnalysisFail;
},
@@ -7940,6 +8015,7 @@ fn analyzeParameter(
is_generic: *bool,
is_extern: bool,
cc: std.builtin.CallingConvention,
+ has_body: bool,
) !void {
const requires_comptime = try sema.typeRequiresComptime(block, param_src, param.ty);
comptime_params[i] = param.is_comptime or requires_comptime;
@@ -7988,9 +8064,9 @@ fn analyzeParameter(
};
return sema.failWithOwnedErrorMsg(msg);
}
- if (requires_comptime and !param.is_comptime) {
+ if (!sema.is_generic_instantiation and requires_comptime and !param.is_comptime and has_body) {
const msg = msg: {
- const msg = try sema.errMsg(block, param_src, "parametter of type '{}' must be declared comptime", .{
+ const msg = try sema.errMsg(block, param_src, "parameter of type '{}' must be declared comptime", .{
param.ty.fmt(sema.mod),
});
errdefer msg.destroy(sema.gpa);
@@ -8088,7 +8164,7 @@ fn zirParam(
try block.params.append(sema.gpa, .{
.ty = param_ty,
- .is_comptime = is_comptime,
+ .is_comptime = comptime_syntax,
.name = param_name,
});
const result = try sema.addConstant(param_ty, Value.initTag(.generic_poison));
@@ -8774,13 +8850,11 @@ fn zirSwitchCapture(
switch (operand_ty.zigTypeTag()) {
.Union => {
const union_obj = operand_ty.cast(Type.Payload.Union).?.data;
- const enum_ty = union_obj.tag_ty;
-
const first_item = try sema.resolveInst(items[0]);
// Previous switch validation ensured this will succeed
const first_item_val = sema.resolveConstValue(block, .unneeded, first_item, undefined) catch unreachable;
- const first_field_index = @intCast(u32, enum_ty.enumTagFieldIndex(first_item_val, sema.mod).?);
+ const first_field_index = @intCast(u32, operand_ty.unionTagFieldIndex(first_item_val, sema.mod).?);
const first_field = union_obj.fields.values()[first_field_index];
for (items[1..]) |item, i| {
@@ -8788,7 +8862,7 @@ fn zirSwitchCapture(
// Previous switch validation ensured this will succeed
const item_val = sema.resolveConstValue(block, .unneeded, item_ref, undefined) catch unreachable;
- const field_index = enum_ty.enumTagFieldIndex(item_val, sema.mod).?;
+ const field_index = operand_ty.unionTagFieldIndex(item_val, sema.mod).?;
const field = union_obj.fields.values()[field_index];
if (!field.ty.eql(first_field.ty, sema.mod)) {
const msg = msg: {
@@ -15521,7 +15595,9 @@ fn unionInit(
const init = try sema.coerce(block, field.ty, uncasted_init, init_src);
if (try sema.resolveMaybeUndefVal(block, init_src, init)) |init_val| {
- const tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);
+ const tag_ty = union_ty.unionTagTypeHypothetical();
+ const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
+ const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
return sema.addConstant(union_ty, try Value.Tag.@"union".create(sema.arena, .{
.tag = tag_val,
.val = init_val,
@@ -15619,7 +15695,9 @@ fn zirStructInit(
const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src);
- const tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);
+ const tag_ty = resolved_ty.unionTagTypeHypothetical();
+ const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
+ const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
const init_inst = try sema.resolveInst(item.data.init);
if (try sema.resolveMaybeUndefVal(block, field_src, init_inst)) |val| {
@@ -16251,7 +16329,7 @@ fn zirUnaryMath(
block: *Block,
inst: Zir.Inst.Index,
air_tag: Air.Inst.Tag,
- eval: fn (Value, Type, Allocator, std.Target) Allocator.Error!Value,
+ comptime eval: fn (Value, Type, Allocator, std.Target) Allocator.Error!Value,
) CompileError!Air.Inst.Ref {
const tracy = trace(@src());
defer tracy.end();
@@ -16384,9 +16462,8 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src);
const val = try sema.resolveConstValue(block, operand_src, type_info, "operand to @Type must be comptime known");
const union_val = val.cast(Value.Payload.Union).?.data;
- const tag_ty = type_info_ty.unionTagType().?;
const target = mod.getTarget();
- const tag_index = tag_ty.enumTagFieldIndex(union_val.tag, mod).?;
+ const tag_index = type_info_ty.unionTagFieldIndex(union_val.tag, mod).?;
if (union_val.val.anyUndef()) return sema.failWithUseOfUndef(block, src);
switch (@intToEnum(std.builtin.TypeId, tag_index)) {
.Type => return Air.Inst.Ref.type_type,
@@ -17711,7 +17788,7 @@ fn zirBitCount(
block: *Block,
inst: Zir.Inst.Index,
air_tag: Air.Inst.Tag,
- comptimeOp: fn (val: Value, ty: Type, target: std.Target) u64,
+ comptime comptimeOp: fn (val: Value, ty: Type, target: std.Target) u64,
) CompileError!Air.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
@@ -20488,8 +20565,8 @@ fn validatePackedType(ty: Type) bool {
.AnyFrame,
.Fn,
.Array,
- .Optional,
=> return false,
+ .Optional => return ty.isPtrLikeOptional(),
.Void,
.Bool,
.Float,
@@ -21317,14 +21394,30 @@ fn fieldCallBind(
switch (concrete_ty.zigTypeTag()) {
.Struct => {
const struct_ty = try sema.resolveTypeFields(block, src, concrete_ty);
- const struct_obj = struct_ty.castTag(.@"struct").?.data;
-
- const field_index_usize = struct_obj.fields.getIndex(field_name) orelse
- break :find_field;
- const field_index = @intCast(u32, field_index_usize);
- const field = struct_obj.fields.values()[field_index];
+ if (struct_ty.castTag(.@"struct")) |struct_obj| {
+ const field_index_usize = struct_obj.data.fields.getIndex(field_name) orelse
+ break :find_field;
+ const field_index = @intCast(u32, field_index_usize);
+ const field = struct_obj.data.fields.values()[field_index];
- return finishFieldCallBind(sema, block, src, ptr_ty, field.ty, field_index, object_ptr);
+ return finishFieldCallBind(sema, block, src, ptr_ty, field.ty, field_index, object_ptr);
+ } else if (struct_ty.isTuple()) {
+ if (mem.eql(u8, field_name, "len")) {
+ return sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount());
+ }
+ if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| {
+ if (field_index >= struct_ty.structFieldCount()) break :find_field;
+ return finishFieldCallBind(sema, block, src, ptr_ty, struct_ty.structFieldType(field_index), field_index, object_ptr);
+ } else |_| {}
+ } else {
+ const max = struct_ty.structFieldCount();
+ var i: u32 = 0;
+ while (i < max) : (i += 1) {
+ if (mem.eql(u8, struct_ty.structFieldName(i), field_name)) {
+ return finishFieldCallBind(sema, block, src, ptr_ty, struct_ty.structFieldType(i), i, object_ptr);
+ }
+ }
+ }
},
.Union => {
const union_ty = try sema.resolveTypeFields(block, src, concrete_ty);
@@ -22487,7 +22580,7 @@ fn coerceExtra(
// Function body to function pointer.
if (inst_ty.zigTypeTag() == .Fn) {
const fn_val = try sema.resolveConstValue(block, .unneeded, inst, undefined);
- const fn_decl = fn_val.castTag(.function).?.data.owner_decl;
+ const fn_decl = fn_val.pointerDecl().?;
const inst_as_ptr = try sema.analyzeDeclRef(fn_decl);
return sema.coerce(block, dest_ty, inst_as_ptr, inst_src);
}
@@ -25091,8 +25184,7 @@ fn coerceEnumToUnion(
const enum_tag = try sema.coerce(block, tag_ty, inst, inst_src);
if (try sema.resolveDefinedValue(block, inst_src, enum_tag)) |val| {
- const union_obj = union_ty.cast(Type.Payload.Union).?.data;
- const field_index = union_obj.tag_ty.enumTagFieldIndex(val, sema.mod) orelse {
+ const field_index = union_ty.unionTagFieldIndex(val, sema.mod) orelse {
const msg = msg: {
const msg = try sema.errMsg(block, inst_src, "union '{}' has no tag with value '{}'", .{
union_ty.fmt(sema.mod), val.fmtValue(tag_ty, sema.mod),
@@ -25103,6 +25195,8 @@ fn coerceEnumToUnion(
};
return sema.failWithOwnedErrorMsg(msg);
};
+
+ const union_obj = union_ty.cast(Type.Payload.Union).?.data;
const field = union_obj.fields.values()[field_index];
const field_ty = try sema.resolveTypeFields(block, inst_src, field.ty);
if (field_ty.zigTypeTag() == .NoReturn) {
@@ -27842,7 +27936,9 @@ fn resolveInferredErrorSetTy(
fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void {
const gpa = mod.gpa;
const decl_index = struct_obj.owner_decl;
- const zir = struct_obj.namespace.file_scope.zir;
+ const file_scope = struct_obj.namespace.file_scope;
+ if (file_scope.status != .success_zir) return error.AnalysisFail;
+ const zir = file_scope.zir;
const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended;
assert(extended.opcode == .struct_decl);
const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
@@ -29422,7 +29518,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ
=> {
const child_ty = ty.childType();
if (child_ty.zigTypeTag() == .Fn) {
- return false;
+ return child_ty.fnInfo().is_generic;
} else {
return sema.typeRequiresComptime(block, src, child_ty);
}
diff --git a/src/codegen.zig b/src/codegen.zig
index 025decdb4b..f5340458a5 100644
--- a/src/codegen.zig
+++ b/src/codegen.zig
@@ -607,7 +607,7 @@ pub fn generateSymbol(
const union_ty = typed_value.ty.cast(Type.Payload.Union).?.data;
const mod = bin_file.options.module.?;
- const field_index = union_ty.tag_ty.enumTagFieldIndex(union_obj.tag, mod).?;
+ const field_index = typed_value.ty.unionTagFieldIndex(union_obj.tag, mod).?;
assert(union_ty.haveFieldTypes());
const field_ty = union_ty.fields.values()[field_index].ty;
if (!field_ty.hasRuntimeBits()) {
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 81a892183f..4a09c09cc9 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -835,7 +835,6 @@ pub const DeclGen = struct {
},
.Union => {
const union_obj = val.castTag(.@"union").?.data;
- const union_ty = ty.cast(Type.Payload.Union).?.data;
const layout = ty.unionGetLayout(target);
try writer.writeAll("(");
@@ -851,7 +850,7 @@ pub const DeclGen = struct {
try writer.writeAll(".payload = {");
}
- const index = union_ty.tag_ty.enumTagFieldIndex(union_obj.tag, dg.module).?;
+ const index = ty.unionTagFieldIndex(union_obj.tag, dg.module).?;
const field_ty = ty.unionFields().values()[index].ty;
const field_name = ty.unionFields().keys()[index];
if (field_ty.hasRuntimeBits()) {
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index d50b463606..cddbdc6822 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -3417,7 +3417,10 @@ pub const DeclGen = struct {
});
const ty_bit_size = @intCast(u16, field.ty.bitSize(target));
const small_int_ty = dg.context.intType(ty_bit_size);
- const small_int_val = non_int_val.constBitCast(small_int_ty);
+ const small_int_val = if (field.ty.isPtrAtRuntime())
+ non_int_val.constPtrToInt(small_int_ty)
+ else
+ non_int_val.constBitCast(small_int_ty);
const shift_rhs = int_llvm_ty.constInt(running_bits, .False);
// If the field is as large as the entire packed struct, this
// zext would go from, e.g. i16 to i16. This is legal with
@@ -3502,7 +3505,7 @@ pub const DeclGen = struct {
});
}
const union_obj = tv.ty.cast(Type.Payload.Union).?.data;
- const field_index = union_obj.tag_ty.enumTagFieldIndex(tag_and_val.tag, dg.module).?;
+ const field_index = tv.ty.unionTagFieldIndex(tag_and_val.tag, dg.module).?;
assert(union_obj.haveFieldTypes());
// Sometimes we must make an unnamed struct because LLVM does
@@ -4016,6 +4019,9 @@ pub const FuncGen = struct {
/// Note that this can disagree with isByRef for the return type in the case
/// of C ABI functions.
ret_ptr: ?*const llvm.Value,
+ /// Any function that needs to perform Valgrind client requests needs an array alloca
+ /// instruction, however a maximum of one per function is needed.
+ valgrind_client_request_array: ?*const llvm.Value = null,
/// These fields are used to refer to the LLVM value of the function parameters
/// in an Arg instruction.
/// This list may be shorter than the list according to the zig type system;
@@ -5343,7 +5349,7 @@ pub const FuncGen = struct {
const same_size_int = self.context.intType(elem_bits);
const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
return self.builder.buildBitCast(truncated_int, elem_llvm_ty, "");
- } else if (field_ty.zigTypeTag() == .Pointer) {
+ } else if (field_ty.isPtrAtRuntime()) {
const elem_bits = @intCast(c_uint, field_ty.bitSize(target));
const same_size_int = self.context.intType(elem_bits);
const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
@@ -7527,8 +7533,7 @@ pub const FuncGen = struct {
const len = usize_llvm_ty.constInt(operand_size, .False);
_ = self.builder.buildMemSet(dest_ptr_u8, fill_char, len, dest_ptr_align, ptr_ty.isVolatilePtr());
if (self.dg.module.comp.bin_file.options.valgrind) {
- // TODO generate valgrind client request to mark byte range as undefined
- // see gen_valgrind_undef() in codegen.cpp
+ self.valgrindMarkUndef(dest_ptr, len);
}
} else {
const src_operand = try self.resolveInst(bin_op.rhs);
@@ -7787,8 +7792,7 @@ pub const FuncGen = struct {
_ = self.builder.buildMemSet(dest_ptr_u8, fill_char, len, dest_ptr_align, ptr_ty.isVolatilePtr());
if (val_is_undef and self.dg.module.comp.bin_file.options.valgrind) {
- // TODO generate valgrind client request to mark byte range as undefined
- // see gen_valgrind_undef() in codegen.cpp
+ self.valgrindMarkUndef(dest_ptr_u8, len);
}
return null;
}
@@ -8408,7 +8412,7 @@ pub const FuncGen = struct {
const non_int_val = try self.resolveInst(elem);
const ty_bit_size = @intCast(u16, field.ty.bitSize(target));
const small_int_ty = self.dg.context.intType(ty_bit_size);
- const small_int_val = if (field.ty.zigTypeTag() == .Pointer)
+ const small_int_val = if (field.ty.isPtrAtRuntime())
self.builder.buildPtrToInt(non_int_val, small_int_ty, "")
else
self.builder.buildBitCast(non_int_val, small_int_ty, "");
@@ -9095,6 +9099,89 @@ pub const FuncGen = struct {
info.@"volatile",
);
}
+
+ fn valgrindMarkUndef(fg: *FuncGen, ptr: *const llvm.Value, len: *const llvm.Value) void {
+ const VG_USERREQ__MAKE_MEM_UNDEFINED = 1296236545;
+ const target = fg.dg.module.getTarget();
+ const usize_llvm_ty = fg.context.intType(target.cpu.arch.ptrBitWidth());
+ const zero = usize_llvm_ty.constInt(0, .False);
+ const req = usize_llvm_ty.constInt(VG_USERREQ__MAKE_MEM_UNDEFINED, .False);
+ const ptr_as_usize = fg.builder.buildPtrToInt(ptr, usize_llvm_ty, "");
+ _ = valgrindClientRequest(fg, zero, req, ptr_as_usize, len, zero, zero, zero);
+ }
+
+ fn valgrindClientRequest(
+ fg: *FuncGen,
+ default_value: *const llvm.Value,
+ request: *const llvm.Value,
+ a1: *const llvm.Value,
+ a2: *const llvm.Value,
+ a3: *const llvm.Value,
+ a4: *const llvm.Value,
+ a5: *const llvm.Value,
+ ) *const llvm.Value {
+ const target = fg.dg.module.getTarget();
+ if (!target_util.hasValgrindSupport(target)) return default_value;
+
+ const usize_llvm_ty = fg.context.intType(target.cpu.arch.ptrBitWidth());
+ const usize_alignment = @intCast(c_uint, Type.usize.abiSize(target));
+
+ switch (target.cpu.arch) {
+ .x86_64 => {
+ const array_ptr = fg.valgrind_client_request_array orelse a: {
+ const array_ptr = fg.buildAlloca(usize_llvm_ty.arrayType(6));
+ array_ptr.setAlignment(usize_alignment);
+ fg.valgrind_client_request_array = array_ptr;
+ break :a array_ptr;
+ };
+ const array_elements = [_]*const llvm.Value{ request, a1, a2, a3, a4, a5 };
+ const zero = usize_llvm_ty.constInt(0, .False);
+ for (array_elements) |elem, i| {
+ const indexes = [_]*const llvm.Value{
+ zero, usize_llvm_ty.constInt(@intCast(c_uint, i), .False),
+ };
+ const elem_ptr = fg.builder.buildInBoundsGEP(array_ptr, &indexes, indexes.len, "");
+ const store_inst = fg.builder.buildStore(elem, elem_ptr);
+ store_inst.setAlignment(usize_alignment);
+ }
+
+ const asm_template =
+ \\rolq $$3, %rdi ; rolq $$13, %rdi
+ \\rolq $$61, %rdi ; rolq $$51, %rdi
+ \\xchgq %rbx,%rbx
+ ;
+
+ const asm_constraints = "={rdx},{rax},0,~{cc},~{memory}";
+
+ const array_ptr_as_usize = fg.builder.buildPtrToInt(array_ptr, usize_llvm_ty, "");
+ const args = [_]*const llvm.Value{ array_ptr_as_usize, default_value };
+ const param_types = [_]*const llvm.Type{ usize_llvm_ty, usize_llvm_ty };
+ const fn_llvm_ty = llvm.functionType(usize_llvm_ty, &param_types, args.len, .False);
+ const asm_fn = llvm.getInlineAsm(
+ fn_llvm_ty,
+ asm_template,
+ asm_template.len,
+ asm_constraints,
+ asm_constraints.len,
+ .True, // has side effects
+ .False, // alignstack
+ .ATT,
+ .False,
+ );
+
+ const call = fg.builder.buildCall(
+ asm_fn,
+ &args,
+ args.len,
+ .C,
+ .Auto,
+ "",
+ );
+ return call;
+ },
+ else => unreachable,
+ }
+ }
};
fn initializeLLVMTarget(arch: std.Target.Cpu.Arch) void {
diff --git a/src/link/Coff.zig b/src/link/Coff.zig
index a01b9cf7c3..6536fbd1ac 100644
--- a/src/link/Coff.zig
+++ b/src/link/Coff.zig
@@ -204,15 +204,18 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
index += 2;
// Characteristics
- var characteristics: u16 = std.coff.IMAGE_FILE_DEBUG_STRIPPED | std.coff.IMAGE_FILE_RELOCS_STRIPPED; // TODO Remove debug info stripped flag when necessary
+ var characteristics: std.coff.CoffHeaderFlags = .{
+ .DEBUG_STRIPPED = 1, // TODO remove debug info stripped flag when necessary
+ .RELOCS_STRIPPED = 1,
+ };
if (options.output_mode == .Exe) {
- characteristics |= std.coff.IMAGE_FILE_EXECUTABLE_IMAGE;
+ characteristics.EXECUTABLE_IMAGE = 1;
}
switch (self.ptr_width) {
- .p32 => characteristics |= std.coff.IMAGE_FILE_32BIT_MACHINE,
- .p64 => characteristics |= std.coff.IMAGE_FILE_LARGE_ADDRESS_AWARE,
+ .p32 => characteristics.@"32BIT_MACHINE" = 1,
+ .p64 => characteristics.LARGE_ADDRESS_AWARE = 1,
}
- mem.writeIntLittle(u16, hdr_data[index..][0..2], characteristics);
+ mem.writeIntLittle(u16, hdr_data[index..][0..2], @bitCast(u16, characteristics));
index += 2;
assert(index == 20);
@@ -352,7 +355,10 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
mem.set(u8, hdr_data[index..][0..12], 0);
index += 12;
// Section flags
- mem.writeIntLittle(u32, hdr_data[index..][0..4], std.coff.IMAGE_SCN_CNT_INITIALIZED_DATA | std.coff.IMAGE_SCN_MEM_READ);
+ mem.writeIntLittle(u32, hdr_data[index..][0..4], @bitCast(u32, std.coff.SectionHeaderFlags{
+ .CNT_INITIALIZED_DATA = 1,
+ .MEM_READ = 1,
+ }));
index += 4;
// Then, the .text section
hdr_data[index..][0..8].* = ".text\x00\x00\x00".*;
@@ -378,11 +384,12 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
mem.set(u8, hdr_data[index..][0..12], 0);
index += 12;
// Section flags
- mem.writeIntLittle(
- u32,
- hdr_data[index..][0..4],
- std.coff.IMAGE_SCN_CNT_CODE | std.coff.IMAGE_SCN_MEM_EXECUTE | std.coff.IMAGE_SCN_MEM_READ | std.coff.IMAGE_SCN_MEM_WRITE,
- );
+ mem.writeIntLittle(u32, hdr_data[index..][0..4], @bitCast(u32, std.coff.SectionHeaderFlags{
+ .CNT_CODE = 1,
+ .MEM_EXECUTE = 1,
+ .MEM_READ = 1,
+ .MEM_WRITE = 1,
+ }));
index += 4;
assert(index == optional_header_size + section_table_size);
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
index 7c04972e4c..91eaedc734 100644
--- a/src/link/MachO.zig
+++ b/src/link/MachO.zig
@@ -5861,8 +5861,9 @@ pub fn generateSymbolStabs(
},
else => |e| return e,
};
- const tu_name = try compile_unit.die.getAttrString(&debug_info, dwarf.AT.name);
- const tu_comp_dir = try compile_unit.die.getAttrString(&debug_info, dwarf.AT.comp_dir);
+
+ const tu_name = try compile_unit.die.getAttrString(&debug_info, dwarf.AT.name, debug_info.debug_str);
+ const tu_comp_dir = try compile_unit.die.getAttrString(&debug_info, dwarf.AT.comp_dir, debug_info.debug_str);
// Open scope
try locals.ensureUnusedCapacity(3);
diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig
index 935183bbc6..22627975f2 100644
--- a/src/link/MachO/Object.zig
+++ b/src/link/MachO/Object.zig
@@ -580,9 +580,15 @@ pub fn parseDwarfInfo(self: Object) error{Overflow}!dwarf.DwarfInfo {
.debug_info = &[0]u8{},
.debug_abbrev = &[0]u8{},
.debug_str = &[0]u8{},
+ .debug_str_offsets = null,
.debug_line = &[0]u8{},
.debug_line_str = &[0]u8{},
.debug_ranges = &[0]u8{},
+ .debug_loclists = &[0]u8{},
+ .debug_rnglists = &[0]u8{},
+ .debug_addr = &[0]u8{},
+ .debug_names = &[0]u8{},
+ .debug_frame = &[0]u8{},
};
for (self.sections.items) |sect| {
const segname = sect.segName();
@@ -600,6 +606,16 @@ pub fn parseDwarfInfo(self: Object) error{Overflow}!dwarf.DwarfInfo {
di.debug_line_str = try self.getSectionContents(sect);
} else if (mem.eql(u8, sectname, "__debug_ranges")) {
di.debug_ranges = try self.getSectionContents(sect);
+ } else if (mem.eql(u8, sectname, "__debug_loclists")) {
+ di.debug_loclists = try self.getSectionContents(sect);
+ } else if (mem.eql(u8, sectname, "__debug_rnglists")) {
+ di.debug_rnglists = try self.getSectionContents(sect);
+ } else if (mem.eql(u8, sectname, "__debug_addr")) {
+ di.debug_addr = try self.getSectionContents(sect);
+ } else if (mem.eql(u8, sectname, "__debug_names")) {
+ di.debug_names = try self.getSectionContents(sect);
+ } else if (mem.eql(u8, sectname, "__debug_frame")) {
+ di.debug_frame = try self.getSectionContents(sect);
}
}
}
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index 626f176652..37e25e4360 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -378,7 +378,7 @@ fn parseObjectFile(self: *Wasm, path: []const u8) !bool {
const file = try fs.cwd().openFile(path, .{});
errdefer file.close();
- var object = Object.create(self.base.allocator, file, path) catch |err| switch (err) {
+ var object = Object.create(self.base.allocator, file, path, null) catch |err| switch (err) {
error.InvalidMagicByte, error.NotObjectFile => return false,
else => |e| return e,
};
@@ -595,8 +595,8 @@ fn resolveSymbolsInArchives(self: *Wasm) !void {
// Parse object and and resolve symbols again before we check remaining
// undefined symbols.
const object_file_index = @intCast(u16, self.objects.items.len);
- const object = try self.objects.addOne(self.base.allocator);
- object.* = try archive.parseObject(self.base.allocator, offset.items[0]);
+ var object = try archive.parseObject(self.base.allocator, offset.items[0]);
+ try self.objects.append(self.base.allocator, object);
try self.resolveSymbolsInObject(object_file_index);
// continue loop for any remaining undefined symbols that still exist
@@ -860,7 +860,8 @@ fn getGlobalType(self: *const Wasm, loc: SymbolLoc) wasm.GlobalType {
if (is_undefined) {
return obj.findImport(.global, symbol.index).kind.global;
}
- return obj.globals[symbol.index].global_type;
+ const import_global_count = obj.importedCountByKind(.global);
+ return obj.globals[symbol.index - import_global_count].global_type;
}
if (is_undefined) {
return self.imports.get(loc).?.kind.global;
@@ -880,7 +881,9 @@ fn getFunctionSignature(self: *const Wasm, loc: SymbolLoc) wasm.Type {
const ty_index = obj.findImport(.function, symbol.index).kind.function;
return obj.func_types[ty_index];
}
- return obj.func_types[obj.functions[symbol.index].type_index];
+ const import_function_count = obj.importedCountByKind(.function);
+ const type_index = obj.functions[symbol.index - import_function_count].type_index;
+ return obj.func_types[type_index];
}
if (is_undefined) {
const ty_index = self.imports.get(loc).?.kind.function;
diff --git a/src/link/Wasm/Archive.zig b/src/link/Wasm/Archive.zig
index e214d1b124..c80d26d17d 100644
--- a/src/link/Wasm/Archive.zig
+++ b/src/link/Wasm/Archive.zig
@@ -15,6 +15,12 @@ name: []const u8,
header: ar_hdr = undefined,
+/// A list of long file names, delimited by a LF character (0x0a).
+/// This is stored as a single slice of bytes, as the header-names
+/// point to the character index of a file name, rather than the index
+/// in the list.
+long_file_names: []const u8 = undefined,
+
/// Parsed table of contents.
/// Each symbol name points to a list of all definition
/// sites within the current static archive.
@@ -53,32 +59,33 @@ const ar_hdr = extern struct {
/// Always contains ARFMAG.
ar_fmag: [2]u8,
- const NameOrLength = union(enum) {
- Name: []const u8,
- Length: u32,
+ const NameOrIndex = union(enum) {
+ name: []const u8,
+ index: u32,
};
- fn nameOrLength(self: ar_hdr) !NameOrLength {
- const value = getValue(&self.ar_name);
+
+ fn nameOrIndex(archive: ar_hdr) !NameOrIndex {
+ const value = getValue(&archive.ar_name);
const slash_index = mem.indexOfScalar(u8, value, '/') orelse return error.MalformedArchive;
const len = value.len;
if (slash_index == len - 1) {
// Name stored directly
- return NameOrLength{ .Name = value };
+ return NameOrIndex{ .name = value };
} else {
// Name follows the header directly and its length is encoded in
// the name field.
- const length = try std.fmt.parseInt(u32, value[slash_index + 1 ..], 10);
- return NameOrLength{ .Length = length };
+ const index = try std.fmt.parseInt(u32, value[slash_index + 1 ..], 10);
+ return NameOrIndex{ .index = index };
}
}
- fn date(self: ar_hdr) !u64 {
- const value = getValue(&self.ar_date);
+ fn date(archive: ar_hdr) !u64 {
+ const value = getValue(&archive.ar_date);
return std.fmt.parseInt(u64, value, 10);
}
- fn size(self: ar_hdr) !u32 {
- const value = getValue(&self.ar_size);
+ fn size(archive: ar_hdr) !u32 {
+ const value = getValue(&archive.ar_size);
return std.fmt.parseInt(u32, value, 10);
}
@@ -87,18 +94,19 @@ const ar_hdr = extern struct {
}
};
-pub fn deinit(self: *Archive, allocator: Allocator) void {
- for (self.toc.keys()) |*key| {
+pub fn deinit(archive: *Archive, allocator: Allocator) void {
+ for (archive.toc.keys()) |*key| {
allocator.free(key.*);
}
- for (self.toc.values()) |*value| {
+ for (archive.toc.values()) |*value| {
value.deinit(allocator);
}
- self.toc.deinit(allocator);
+ archive.toc.deinit(allocator);
+ allocator.free(archive.long_file_names);
}
-pub fn parse(self: *Archive, allocator: Allocator) !void {
- const reader = self.file.reader();
+pub fn parse(archive: *Archive, allocator: Allocator) !void {
+ const reader = archive.file.reader();
const magic = try reader.readBytesNoEof(SARMAG);
if (!mem.eql(u8, &magic, ARMAG)) {
@@ -106,38 +114,31 @@ pub fn parse(self: *Archive, allocator: Allocator) !void {
return error.NotArchive;
}
- self.header = try reader.readStruct(ar_hdr);
- if (!mem.eql(u8, &self.header.ar_fmag, ARFMAG)) {
- log.debug("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, self.header.ar_fmag });
+ archive.header = try reader.readStruct(ar_hdr);
+ if (!mem.eql(u8, &archive.header.ar_fmag, ARFMAG)) {
+ log.debug("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, archive.header.ar_fmag });
return error.NotArchive;
}
- try self.parseTableOfContents(allocator, reader);
+ try archive.parseTableOfContents(allocator, reader);
+ try archive.parseNameTable(allocator, reader);
}
-fn parseName(allocator: Allocator, header: ar_hdr, reader: anytype) ![]u8 {
- const name_or_length = try header.nameOrLength();
- var name: []u8 = undefined;
- switch (name_or_length) {
- .Name => |n| {
- name = try allocator.dupe(u8, n);
- },
- .Length => |len| {
- var n = try allocator.alloc(u8, len);
- defer allocator.free(n);
- try reader.readNoEof(n);
- const actual_len = mem.indexOfScalar(u8, n, @as(u8, 0)) orelse n.len;
- name = try allocator.dupe(u8, n[0..actual_len]);
+fn parseName(archive: *const Archive, header: ar_hdr) ![]const u8 {
+ const name_or_index = try header.nameOrIndex();
+ switch (name_or_index) {
+ .name => |name| return name,
+ .index => |index| {
+ const name = mem.sliceTo(archive.long_file_names[index..], 0x0a);
+ return mem.trimRight(u8, name, "/");
},
}
- return name;
}
-fn parseTableOfContents(self: *Archive, allocator: Allocator, reader: anytype) !void {
- log.debug("parsing table of contents for archive file '{s}'", .{self.name});
+fn parseTableOfContents(archive: *Archive, allocator: Allocator, reader: anytype) !void {
// size field can have extra spaces padded in front as well as the end,
// so we trim those first before parsing the ASCII value.
- const size_trimmed = std.mem.trim(u8, &self.header.ar_size, " ");
+ const size_trimmed = mem.trim(u8, &archive.header.ar_size, " ");
const sym_tab_size = try std.fmt.parseInt(u32, size_trimmed, 10);
const num_symbols = try reader.readIntBig(u32);
@@ -157,7 +158,7 @@ fn parseTableOfContents(self: *Archive, allocator: Allocator, reader: anytype) !
var i: usize = 0;
while (i < sym_tab.len) {
- const string = std.mem.sliceTo(sym_tab[i..], 0);
+ const string = mem.sliceTo(sym_tab[i..], 0);
if (string.len == 0) {
i += 1;
continue;
@@ -165,7 +166,7 @@ fn parseTableOfContents(self: *Archive, allocator: Allocator, reader: anytype) !
i += string.len;
const name = try allocator.dupe(u8, string);
errdefer allocator.free(name);
- const gop = try self.toc.getOrPut(allocator, name);
+ const gop = try archive.toc.getOrPut(allocator, name);
if (gop.found_existing) {
allocator.free(name);
} else {
@@ -175,33 +176,49 @@ fn parseTableOfContents(self: *Archive, allocator: Allocator, reader: anytype) !
}
}
+fn parseNameTable(archive: *Archive, allocator: Allocator, reader: anytype) !void {
+ const header: ar_hdr = try reader.readStruct(ar_hdr);
+ if (!mem.eql(u8, &header.ar_fmag, ARFMAG)) {
+ log.err("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, header.ar_fmag });
+ return error.MalformedArchive;
+ }
+ if (!mem.eql(u8, header.ar_name[0..2], "//")) {
+ log.err("invalid archive. Long name table missing", .{});
+ return error.MalformedArchive;
+ }
+ const table_size = try header.size();
+ const long_file_names = try allocator.alloc(u8, table_size);
+ errdefer allocator.free(long_file_names);
+ try reader.readNoEof(long_file_names);
+ archive.long_file_names = long_file_names;
+}
+
/// From a given file offset, starts reading for a file header.
/// When found, parses the object file into an `Object` and returns it.
-pub fn parseObject(self: Archive, allocator: Allocator, file_offset: u32) !Object {
- try self.file.seekTo(file_offset);
- const reader = self.file.reader();
+pub fn parseObject(archive: Archive, allocator: Allocator, file_offset: u32) !Object {
+ try archive.file.seekTo(file_offset);
+ const reader = archive.file.reader();
const header = try reader.readStruct(ar_hdr);
- const current_offset = try self.file.getPos();
- try self.file.seekTo(0);
+ const current_offset = try archive.file.getPos();
+ try archive.file.seekTo(0);
if (!mem.eql(u8, &header.ar_fmag, ARFMAG)) {
log.err("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, header.ar_fmag });
return error.MalformedArchive;
}
- const object_name = try parseName(allocator, header, reader);
- defer allocator.free(object_name);
-
+ const object_name = try archive.parseName(header);
const name = name: {
var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
- const path = try std.os.realpath(self.name, &buffer);
+ const path = try std.os.realpath(archive.name, &buffer);
break :name try std.fmt.allocPrint(allocator, "{s}({s})", .{ path, object_name });
};
defer allocator.free(name);
- const object_file = try std.fs.cwd().openFile(self.name, .{});
+ const object_file = try std.fs.cwd().openFile(archive.name, .{});
errdefer object_file.close();
+ const object_file_size = try header.size();
try object_file.seekTo(current_offset);
- return Object.create(allocator, object_file, name);
+ return Object.create(allocator, object_file, name, object_file_size);
}
diff --git a/src/link/Wasm/Object.zig b/src/link/Wasm/Object.zig
index a1308ec045..50827ca9fb 100644
--- a/src/link/Wasm/Object.zig
+++ b/src/link/Wasm/Object.zig
@@ -105,14 +105,33 @@ pub const InitError = error{NotObjectFile} || ParseError || std.fs.File.ReadErro
/// Initializes a new `Object` from a wasm object file.
/// This also parses and verifies the object file.
-pub fn create(gpa: Allocator, file: std.fs.File, name: []const u8) InitError!Object {
+/// When a max size is given, will only parse up to the given size,
+/// else will read until the end of the file.
+pub fn create(gpa: Allocator, file: std.fs.File, name: []const u8, maybe_max_size: ?usize) InitError!Object {
var object: Object = .{
.file = file,
.name = try gpa.dupe(u8, name),
};
var is_object_file: bool = false;
- try object.parse(gpa, file.reader(), &is_object_file);
+ const size = maybe_max_size orelse size: {
+ errdefer gpa.free(object.name);
+ const stat = try file.stat();
+ break :size @intCast(usize, stat.size);
+ };
+
+ const file_contents = try gpa.alloc(u8, size);
+ defer gpa.free(file_contents);
+ var file_reader = file.reader();
+ var read: usize = 0;
+ while (read < size) {
+ const n = try file_reader.read(file_contents[read..]);
+ std.debug.assert(n != 0);
+ read += n;
+ }
+ var fbs = std.io.fixedBufferStream(file_contents);
+
+ try object.parse(gpa, fbs.reader(), &is_object_file);
errdefer object.deinit(gpa);
if (!is_object_file) return error.NotObjectFile;
diff --git a/src/type.zig b/src/type.zig
index f6afa33df1..1592dcf469 100644
--- a/src/type.zig
+++ b/src/type.zig
@@ -2394,7 +2394,7 @@ pub const Type = extern union {
if (ignore_comptime_only) {
return true;
} else if (ty.childType().zigTypeTag() == .Fn) {
- return true;
+ return !ty.childType().fnInfo().is_generic;
} else if (sema_kit) |sk| {
return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, ty));
} else {
@@ -4285,11 +4285,18 @@ pub const Type = extern union {
pub fn unionFieldType(ty: Type, enum_tag: Value, mod: *Module) Type {
const union_obj = ty.cast(Payload.Union).?.data;
- const index = union_obj.tag_ty.enumTagFieldIndex(enum_tag, mod).?;
+ const index = ty.unionTagFieldIndex(enum_tag, mod).?;
assert(union_obj.haveFieldTypes());
return union_obj.fields.values()[index].ty;
}
+ pub fn unionTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?usize {
+ const union_obj = ty.cast(Payload.Union).?.data;
+ const index = union_obj.tag_ty.enumTagFieldIndex(enum_tag, mod) orelse return null;
+ const name = union_obj.tag_ty.enumFieldName(index);
+ return union_obj.fields.getIndex(name);
+ }
+
pub fn unionHasAllZeroBitFieldTypes(ty: Type) bool {
return ty.cast(Payload.Union).?.data.hasAllZeroBitFieldTypes();
}
diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp
index 52c202fded..e03d26d7c4 100644
--- a/src/zig_llvm.cpp
+++ b/src/zig_llvm.cpp
@@ -1130,7 +1130,7 @@ void ZigLLVMGetNativeTarget(ZigLLVM_ArchType *arch_type,
void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module) {
unwrap(module)->addModuleFlag(Module::Warning, "Debug Info Version", DEBUG_METADATA_VERSION);
- unwrap(module)->addModuleFlag(Module::Warning, "Dwarf Version", 4);
+ unwrap(module)->addModuleFlag(Module::Warning, "Dwarf Version", 5);
}
void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module) {