diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2024-12-30 15:40:11 -0800 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2025-01-15 15:11:36 -0800 |
| commit | 5b18af85cb77d8dd7b2300bd01c00990d03abde2 (patch) | |
| tree | 1de9ca1604f82d222a15fba0b0f58bbc466f047c /src | |
| parent | a4895f3c42e8bd7d3eba5624e4a11aae5312a085 (diff) | |
| download | zig-5b18af85cb77d8dd7b2300bd01c00990d03abde2.tar.gz zig-5b18af85cb77d8dd7b2300bd01c00990d03abde2.zip | |
type checking for synthetic functions
Diffstat (limited to 'src')
| -rw-r--r-- | src/link.zig | 19 | ||||
| -rw-r--r-- | src/link/Wasm.zig | 79 | ||||
| -rw-r--r-- | src/link/Wasm/Flush.zig | 1 |
3 files changed, 68 insertions, 31 deletions
diff --git a/src/link.zig b/src/link.zig index 17ccb8ac0c..0a3d6f0bb1 100644 --- a/src/link.zig +++ b/src/link.zig @@ -214,22 +214,35 @@ pub const Diags = struct { return error.LinkFailure; } + pub fn failSourceLocation(diags: *Diags, sl: SourceLocation, comptime format: []const u8, args: anytype) error{LinkFailure} { + @branchHint(.cold); + addErrorSourceLocation(diags, sl, format, args); + return error.LinkFailure; + } + pub fn addError(diags: *Diags, comptime format: []const u8, args: anytype) void { + return addErrorSourceLocation(diags, .none, format, args); + } + + pub fn addErrorSourceLocation(diags: *Diags, sl: SourceLocation, comptime format: []const u8, args: anytype) void { @branchHint(.cold); const gpa = diags.gpa; const eu_main_msg = std.fmt.allocPrint(gpa, format, args); diags.mutex.lock(); defer diags.mutex.unlock(); - addErrorLockedFallible(diags, eu_main_msg) catch |err| switch (err) { + addErrorLockedFallible(diags, sl, eu_main_msg) catch |err| switch (err) { error.OutOfMemory => diags.setAllocFailureLocked(), }; } - fn addErrorLockedFallible(diags: *Diags, eu_main_msg: Allocator.Error![]u8) Allocator.Error!void { + fn addErrorLockedFallible(diags: *Diags, sl: SourceLocation, eu_main_msg: Allocator.Error![]u8) Allocator.Error!void { const gpa = diags.gpa; const main_msg = try eu_main_msg; errdefer gpa.free(main_msg); - try diags.msgs.append(gpa, .{ .msg = main_msg }); + try diags.msgs.append(gpa, .{ + .msg = main_msg, + .source_location = sl, + }); } pub fn addErrorWithNotes(diags: *Diags, note_count: usize) error{OutOfMemory}!ErrorWithNotes { diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index cd3554f1dc..58c3a949d9 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -474,6 +474,10 @@ pub const SourceLocation = enum(u32) { err_msg.notes[err.note_slot - 1].source_location = .{ .wasm = sl }; } + pub fn fail(sl: SourceLocation, diags: *link.Diags, comptime format: []const u8, args: anytype) error{LinkFailure} { + return diags.failSourceLocation(.{ .wasm = sl }, format, args); + } + pub fn string( sl: SourceLocation, msg: []const u8, @@ -881,12 +885,11 @@ pub const FunctionImport = extern struct { __wasm_call_ctors, __wasm_init_memory, __wasm_init_tls, - __zig_error_names, // Next, index into `object_functions`. // Next, index into `zcu_funcs`. _, - const first_object_function = @intFromEnum(Resolution.__zig_error_names) + 1; + const first_object_function = @intFromEnum(Resolution.__wasm_init_tls) + 1; pub const Unpacked = union(enum) { unresolved, @@ -894,7 +897,6 @@ pub const FunctionImport = extern struct { __wasm_call_ctors, __wasm_init_memory, __wasm_init_tls, - __zig_error_names, object_function: ObjectFunctionIndex, zcu_func: ZcuFunc.Index, }; @@ -906,7 +908,6 @@ pub const FunctionImport = extern struct { .__wasm_call_ctors => .__wasm_call_ctors, .__wasm_init_memory => .__wasm_init_memory, .__wasm_init_tls => .__wasm_init_tls, - .__zig_error_names => .__zig_error_names, _ => { const object_function_index = @intFromEnum(r) - first_object_function; @@ -927,7 +928,6 @@ pub const FunctionImport = extern struct { .__wasm_call_ctors => .__wasm_call_ctors, .__wasm_init_memory => .__wasm_init_memory, .__wasm_init_tls => .__wasm_init_tls, - .__zig_error_names => .__zig_error_names, .object_function => |i| @enumFromInt(first_object_function + @intFromEnum(i)), .zcu_func => |i| @enumFromInt(first_object_function + wasm.object_functions.items.len + @intFromEnum(i)), }; @@ -957,11 +957,11 @@ pub const FunctionImport = extern struct { pub fn typeIndex(r: Resolution, wasm: *Wasm) FunctionType.Index { return switch (unpack(r, wasm)) { .unresolved => unreachable, - .__wasm_apply_global_tls_relocs => @panic("TODO"), - .__wasm_call_ctors => @panic("TODO"), - .__wasm_init_memory => @panic("TODO"), - .__wasm_init_tls => @panic("TODO"), - .__zig_error_names => @panic("TODO"), + .__wasm_apply_global_tls_relocs, + .__wasm_call_ctors, + .__wasm_init_memory, + => getExistingFuncType2(wasm, &.{}, &.{}), + .__wasm_init_tls => getExistingFuncType2(wasm, &.{.i32}, &.{}), .object_function => |i| i.ptr(wasm).type_index, .zcu_func => |i| i.typeIndex(wasm).?, }; @@ -974,7 +974,6 @@ pub const FunctionImport = extern struct { .__wasm_call_ctors => @tagName(Unpacked.__wasm_call_ctors), .__wasm_init_memory => @tagName(Unpacked.__wasm_init_memory), .__wasm_init_tls => @tagName(Unpacked.__wasm_init_tls), - .__zig_error_names => @tagName(Unpacked.__zig_error_names), .object_function => |i| i.ptr(wasm).name.slice(wasm), .zcu_func => |i| i.name(wasm), }; @@ -2991,7 +2990,7 @@ fn markFunctionImport( name: String, import: *FunctionImport, func_index: FunctionImport.Index, -) Allocator.Error!void { +) link.File.FlushError!void { if (import.flags.alive) return; import.flags.alive = true; @@ -3002,17 +3001,13 @@ fn markFunctionImport( if (import.resolution == .unresolved) { if (name == wasm.preloaded_strings.__wasm_init_memory) { - import.resolution = .__wasm_init_memory; - wasm.functions.putAssumeCapacity(.__wasm_init_memory, {}); + try wasm.resolveFunctionSynthetic(import, .__wasm_init_memory, &.{}, &.{}); } else if (name == wasm.preloaded_strings.__wasm_apply_global_tls_relocs) { - import.resolution = .__wasm_apply_global_tls_relocs; - wasm.functions.putAssumeCapacity(.__wasm_apply_global_tls_relocs, {}); + try wasm.resolveFunctionSynthetic(import, .__wasm_apply_global_tls_relocs, &.{}, &.{}); } else if (name == wasm.preloaded_strings.__wasm_call_ctors) { - import.resolution = .__wasm_call_ctors; - wasm.functions.putAssumeCapacity(.__wasm_call_ctors, {}); + try wasm.resolveFunctionSynthetic(import, .__wasm_call_ctors, &.{}, &.{}); } else if (name == wasm.preloaded_strings.__wasm_init_tls) { - import.resolution = .__wasm_init_tls; - wasm.functions.putAssumeCapacity(.__wasm_init_tls, {}); + try wasm.resolveFunctionSynthetic(import, .__wasm_init_tls, &.{.i32}, &.{}); } else { try wasm.function_imports.put(gpa, name, .fromObject(func_index, wasm)); } @@ -3022,7 +3017,7 @@ fn markFunctionImport( } /// Recursively mark alive everything referenced by the function. -fn markFunction(wasm: *Wasm, i: ObjectFunctionIndex) Allocator.Error!void { +fn markFunction(wasm: *Wasm, i: ObjectFunctionIndex) link.File.FlushError!void { const comp = wasm.base.comp; const gpa = comp.gpa; const gop = try wasm.functions.getOrPut(gpa, .fromObjectFunction(wasm, i)); @@ -3046,7 +3041,7 @@ fn markGlobalImport( name: String, import: *GlobalImport, global_index: GlobalImport.Index, -) !void { +) link.File.FlushError!void { if (import.flags.alive) return; import.flags.alive = true; @@ -3082,7 +3077,7 @@ fn markGlobalImport( } } -fn markGlobal(wasm: *Wasm, i: ObjectGlobalIndex) Allocator.Error!void { +fn markGlobal(wasm: *Wasm, i: ObjectGlobalIndex) link.File.FlushError!void { const comp = wasm.base.comp; const gpa = comp.gpa; const gop = try wasm.globals.getOrPut(gpa, .fromObjectGlobal(wasm, i)); @@ -3105,7 +3100,7 @@ fn markTableImport( name: String, import: *TableImport, table_index: TableImport.Index, -) !void { +) link.File.FlushError!void { if (import.flags.alive) return; import.flags.alive = true; @@ -3127,7 +3122,7 @@ fn markTableImport( } } -fn markDataSegment(wasm: *Wasm, segment_index: ObjectDataSegment.Index) Allocator.Error!void { +fn markDataSegment(wasm: *Wasm, segment_index: ObjectDataSegment.Index) link.File.FlushError!void { const segment = segment_index.ptr(wasm); if (segment.flags.alive) return; segment.flags.alive = true; @@ -3135,7 +3130,7 @@ fn markDataSegment(wasm: *Wasm, segment_index: ObjectDataSegment.Index) Allocato try wasm.markRelocations(segment.relocations(wasm)); } -fn markRelocations(wasm: *Wasm, relocs: ObjectRelocation.IterableSlice) Allocator.Error!void { +fn markRelocations(wasm: *Wasm, relocs: ObjectRelocation.IterableSlice) link.File.FlushError!void { for (relocs.slice.tags(wasm), relocs.slice.pointees(wasm), relocs.slice.offsets(wasm)) |tag, *pointee, offset| { if (offset >= relocs.end) break; switch (tag) { @@ -3751,7 +3746,7 @@ pub fn internValtypeList(wasm: *Wasm, valtype_list: []const std.wasm.Valtype) Al return .fromString(try internString(wasm, @ptrCast(valtype_list))); } -pub fn getExistingValtypeList(wasm: *Wasm, valtype_list: []const std.wasm.Valtype) ?ValtypeList { +pub fn getExistingValtypeList(wasm: *const Wasm, valtype_list: []const std.wasm.Valtype) ?ValtypeList { return .fromString(getExistingString(wasm, @ptrCast(valtype_list)) orelse return null); } @@ -3766,6 +3761,13 @@ pub fn getExistingFuncType(wasm: *const Wasm, ft: FunctionType) ?FunctionType.In return @enumFromInt(index); } +pub fn getExistingFuncType2(wasm: *const Wasm, params: []const std.wasm.Valtype, returns: []const std.wasm.Valtype) FunctionType.Index { + return getExistingFuncType(wasm, .{ + .params = getExistingValtypeList(wasm, params).?, + .returns = getExistingValtypeList(wasm, returns).?, + }).?; +} + pub fn internFunctionType( wasm: *Wasm, cc: std.builtin.CallingConvention, @@ -4080,3 +4082,26 @@ fn addZcuImportReserved(wasm: *Wasm, nav_index: InternPool.Nav.Index) ZcuImportI gop.value_ptr.* = {}; return @enumFromInt(gop.index); } + +fn resolveFunctionSynthetic( + wasm: *Wasm, + import: *FunctionImport, + res: FunctionImport.Resolution, + params: []const std.wasm.Valtype, + returns: []const std.wasm.Valtype, +) link.File.FlushError!void { + import.resolution = res; + wasm.functions.putAssumeCapacity(res, {}); + // This is not only used for type-checking but also ensures the function + // type index is interned so that it is guaranteed to exist during `flush`. + const correct_func_type = try addFuncType(wasm, .{ + .params = try internValtypeList(wasm, params), + .returns = try internValtypeList(wasm, returns), + }); + if (import.type != correct_func_type) { + const diags = &wasm.base.comp.link_diags; + return import.source_location.fail(diags, "synthetic function {s} {} imported with incorrect signature {}", .{ + @tagName(res), correct_func_type.fmt(wasm), import.type.fmt(wasm), + }); + } +} diff --git a/src/link/Wasm/Flush.zig b/src/link/Wasm/Flush.zig index a2fec91c34..91ab224850 100644 --- a/src/link/Wasm/Flush.zig +++ b/src/link/Wasm/Flush.zig @@ -682,7 +682,6 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { .__wasm_call_ctors => @panic("TODO lower __wasm_call_ctors"), .__wasm_init_memory => @panic("TODO lower __wasm_init_memory "), .__wasm_init_tls => @panic("TODO lower __wasm_init_tls "), - .__zig_error_names => @panic("TODO lower __zig_error_names "), .object_function => |i| { _ = i; @panic("TODO lower object function code and apply relocations"); |
