diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Module.zig | 8 | ||||
| -rw-r--r-- | src/Sema.zig | 184 | ||||
| -rw-r--r-- | src/codegen.zig | 2 | ||||
| -rw-r--r-- | src/codegen/c.zig | 3 | ||||
| -rw-r--r-- | src/codegen/llvm.zig | 103 | ||||
| -rw-r--r-- | src/link/Coff.zig | 29 | ||||
| -rw-r--r-- | src/link/MachO.zig | 5 | ||||
| -rw-r--r-- | src/link/MachO/Object.zig | 16 | ||||
| -rw-r--r-- | src/link/Wasm.zig | 13 | ||||
| -rw-r--r-- | src/link/Wasm/Archive.zig | 121 | ||||
| -rw-r--r-- | src/link/Wasm/Object.zig | 23 | ||||
| -rw-r--r-- | src/type.zig | 11 | ||||
| -rw-r--r-- | src/zig_llvm.cpp | 2 |
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, ¶m_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) { |
