From 236af776fd21c76d7ca272f65355767413821011 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Fri, 25 Sep 2020 10:51:57 -0600 Subject: [PATCH 01/55] std.fmt: add comptimePrint --- lib/std/fmt.zig | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index 56a1aba217..0bc5093fb9 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -1181,6 +1181,16 @@ fn bufPrintIntToSlice(buf: []u8, value: anytype, base: u8, uppercase: bool, opti return buf[0..formatIntBuf(buf, value, base, uppercase, options)]; } +pub fn comptimePrint(comptime fmt: []const u8, args: anytype) *const [count(fmt, args)]u8 { + comptime var buf: [count(fmt, args)]u8 = undefined; + _ = bufPrint(&buf, fmt, args) catch |err| @compileError(err); + return &buf; +} + +test "comptimePrint" { + std.testing.expectEqualSlices(u8, "100", comptime comptimePrint("{}", .{100})); +} + test "parse u64 digit too big" { _ = parseUnsigned(u64, "123a", 10) catch |err| { if (err == error.InvalidCharacter) return; From 99c5d2d59053f647c041f71d75ee50f51a610977 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sat, 26 Sep 2020 17:10:33 +0200 Subject: [PATCH 02/55] Print the llvm-config path on configuration error This is helpful on systems with multiple LLVM installations. For example, OpenBSD ships with LLVM in the base system, but without support for extra targets. A full LLVM version can be installed using the ports system, but even when it is, `cmake` is not going to pick it up unless `/usr/local` is explicitly added to the `cmake` search paths. Having the full `llvm-config` path printed on error is helpful to understand that the detected LLVM version was not the expected one. --- cmake/Findllvm.cmake | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmake/Findllvm.cmake b/cmake/Findllvm.cmake index 6bee52c315..59d8e1352b 100644 --- a/cmake/Findllvm.cmake +++ b/cmake/Findllvm.cmake @@ -55,13 +55,13 @@ elseif("${ZIG_TARGET_TRIPLE}" STREQUAL "native") OUTPUT_STRIP_TRAILING_WHITESPACE) if("${LLVM_CONFIG_VERSION}" VERSION_LESS 10) - message(FATAL_ERROR "expected LLVM 10.x but found ${LLVM_CONFIG_VERSION}") + message(FATAL_ERROR "expected LLVM 10.x but found ${LLVM_CONFIG_VERSION} using ${LLVM_CONFIG_EXE}") endif() if("${LLVM_CONFIG_VERSION}" VERSION_EQUAL 11) - message(FATAL_ERROR "expected LLVM 10.x but found ${LLVM_CONFIG_VERSION}") + message(FATAL_ERROR "expected LLVM 10.x but found ${LLVM_CONFIG_VERSION} using ${LLVM_CONFIG_EXE}") endif() if("${LLVM_CONFIG_VERSION}" VERSION_GREATER 11) - message(FATAL_ERROR "expected LLVM 10.x but found ${LLVM_CONFIG_VERSION}") + message(FATAL_ERROR "expected LLVM 10.x but found ${LLVM_CONFIG_VERSION} using ${LLVM_CONFIG_EXE}") endif() execute_process( @@ -72,7 +72,7 @@ elseif("${ZIG_TARGET_TRIPLE}" STREQUAL "native") function(NEED_TARGET TARGET_NAME) list (FIND LLVM_TARGETS_BUILT "${TARGET_NAME}" _index) if (${_index} EQUAL -1) - message(FATAL_ERROR "LLVM is missing target ${TARGET_NAME}. Zig requires LLVM to be built with all default targets enabled.") + message(FATAL_ERROR "LLVM (according to ${LLVM_CONFIG_EXE}) is missing target ${TARGET_NAME}. Zig requires LLVM to be built with all default targets enabled.") endif() endfunction(NEED_TARGET) NEED_TARGET("AArch64") From 16f041970007d997d67ee2e15f0eba1053204808 Mon Sep 17 00:00:00 2001 From: Loris Cro Date: Tue, 29 Sep 2020 14:50:46 +0200 Subject: [PATCH 03/55] add runDetached to event loop Signed-off-by: Loris Cro --- lib/std/event/loop.zig | 53 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/lib/std/event/loop.zig b/lib/std/event/loop.zig index 2ed9f938d8..cb0aa63dbe 100644 --- a/lib/std/event/loop.zig +++ b/lib/std/event/loop.zig @@ -647,6 +647,29 @@ pub const Loop = struct { } } + /// Runs the provided function asynchonously, similarly to Go's "go" operator. + /// `func` must return void and it can be an async function. + fn runDetached(self: *Loop, alloc: *mem.Allocator, comptime func: anytype, args: anytype) error{OutOfMemory}!void { + if (!std.io.is_async) @compileError("Can't use runDetached in non-async mode!"); + if (@TypeOf(@call(.{}, func, args)) != void) { + @compileError("`func` must not have a return value"); + } + + const Wrapper = struct { + const Args = @TypeOf(args); + fn run(func_args: Args, loop: *Loop, allocator: *mem.Allocator) void { + loop.yield(); + const result = @call(.{}, func, func_args); + suspend { + allocator.destroy(@frame()); + } + } + }; + + var run_frame = try alloc.create(@Frame(Wrapper.run)); + run_frame.* = async Wrapper.run(args, self, alloc); + } + /// Yielding lets the event loop run, starting any unstarted async operations. /// Note that async operations automatically start when a function yields for any other reason, /// for example, when async I/O is performed. This function is intended to be used only when @@ -1493,3 +1516,33 @@ fn testEventLoop2(h: anyframe->i32, did_it: *bool) void { testing.expect(value == 1234); did_it.* = true; } + +var testRunDetachedData: usize = 0; +test "std.event.Loop - runDetached" { + // https://github.com/ziglang/zig/issues/1908 + if (builtin.single_threaded) return error.SkipZigTest; + if (!std.io.is_async) return error.SkipZigTest; + if (true) { + // https://github.com/ziglang/zig/issues/4922 + return error.SkipZigTest; + } + + var loop: Loop = undefined; + try loop.initMultiThreaded(); + defer loop.deinit(); + + // Schedule the execution, won't actually start until we start the + // event loop. + try loop.runDetached(std.testing.allocator, testRunDetached, .{}); + + // Now we can start the event loop. The function will return only + // after all tasks have been completed, allowing us to synchonize + // with the previous runDetached. + loop.run(); + + testing.expect(testRunDetachedData == 1); +} + +fn testRunDetached() void { + testRunDetachedData += 1; +} From 4102ba37dda9bf93cf926dee3a7e3e9c1c434989 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Tue, 29 Sep 2020 19:49:13 +0200 Subject: [PATCH 04/55] Fix std.ArrayListUnmanaged + improve test coverage --- lib/std/array_list.zig | 578 +++++++++++++++++++++++++++++------------ 1 file changed, 409 insertions(+), 169 deletions(-) diff --git a/lib/std/array_list.zig b/lib/std/array_list.zig index f298d14631..9144d2c644 100644 --- a/lib/std/array_list.zig +++ b/lib/std/array_list.zig @@ -371,7 +371,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ pub fn initCapacity(allocator: *Allocator, num: usize) !Self { var self = Self{}; - const new_memory = try self.allocator.allocAdvanced(T, alignment, num, .at_least); + const new_memory = try allocator.allocAdvanced(T, alignment, num, .at_least); self.items.ptr = new_memory.ptr; self.capacity = new_memory.len; @@ -419,7 +419,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ /// Replace range of elements `list[start..start+len]` with `new_items` /// grows list if `len < new_items.len`. may allocate /// shrinks list if `len > new_items.len` - pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: SliceConst) !void { + pub fn replaceRange(self: *Self, allocator: *Allocator, start: usize, len: usize, new_items: SliceConst) !void { var managed = self.toManaged(allocator); try managed.replaceRange(start, len, new_items); self.* = managed.toUnmanaged(); @@ -617,201 +617,414 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ }; } -test "std.ArrayList.init" { - var list = ArrayList(i32).init(testing.allocator); - defer list.deinit(); - - testing.expect(list.items.len == 0); - testing.expect(list.capacity == 0); -} - -test "std.ArrayList.initCapacity" { - var list = try ArrayList(i8).initCapacity(testing.allocator, 200); - defer list.deinit(); - testing.expect(list.items.len == 0); - testing.expect(list.capacity >= 200); -} - -test "std.ArrayList.basic" { - var list = ArrayList(i32).init(testing.allocator); - defer list.deinit(); - +test "std.ArrayList/ArrayListUnmanaged.init" { { - var i: usize = 0; - while (i < 10) : (i += 1) { - list.append(@intCast(i32, i + 1)) catch unreachable; - } + var list = ArrayList(i32).init(testing.allocator); + defer list.deinit(); + + testing.expect(list.items.len == 0); + testing.expect(list.capacity == 0); } { - var i: usize = 0; - while (i < 10) : (i += 1) { - testing.expect(list.items[i] == @intCast(i32, i + 1)); + var list = ArrayListUnmanaged(i32){}; + + testing.expect(list.items.len == 0); + testing.expect(list.capacity == 0); + } +} + +test "std.ArrayList/ArrayListUnmanaged.initCapacity" { + const a = testing.allocator; + { + var list = try ArrayList(i8).initCapacity(a, 200); + defer list.deinit(); + testing.expect(list.items.len == 0); + testing.expect(list.capacity >= 200); + } + { + var list = try ArrayListUnmanaged(i8).initCapacity(a, 200); + defer list.deinit(a); + testing.expect(list.items.len == 0); + testing.expect(list.capacity >= 200); + } +} + +test "std.ArrayList/ArrayListUnmanaged.basic" { + const a = testing.allocator; + { + var list = ArrayList(i32).init(a); + defer list.deinit(); + + { + var i: usize = 0; + while (i < 10) : (i += 1) { + list.append(@intCast(i32, i + 1)) catch unreachable; + } + } + + { + var i: usize = 0; + while (i < 10) : (i += 1) { + testing.expect(list.items[i] == @intCast(i32, i + 1)); + } + } + + for (list.items) |v, i| { + testing.expect(v == @intCast(i32, i + 1)); + } + + testing.expect(list.pop() == 10); + testing.expect(list.items.len == 9); + + list.appendSlice(&[_]i32{ 1, 2, 3 }) catch unreachable; + testing.expect(list.items.len == 12); + testing.expect(list.pop() == 3); + testing.expect(list.pop() == 2); + testing.expect(list.pop() == 1); + testing.expect(list.items.len == 9); + + list.appendSlice(&[_]i32{}) catch unreachable; + testing.expect(list.items.len == 9); + + // can only set on indices < self.items.len + list.items[7] = 33; + list.items[8] = 42; + + testing.expect(list.pop() == 42); + testing.expect(list.pop() == 33); + } + { + var list = ArrayListUnmanaged(i32){}; + defer list.deinit(a); + + { + var i: usize = 0; + while (i < 10) : (i += 1) { + list.append(a, @intCast(i32, i + 1)) catch unreachable; + } + } + + { + var i: usize = 0; + while (i < 10) : (i += 1) { + testing.expect(list.items[i] == @intCast(i32, i + 1)); + } + } + + for (list.items) |v, i| { + testing.expect(v == @intCast(i32, i + 1)); + } + + testing.expect(list.pop() == 10); + testing.expect(list.items.len == 9); + + list.appendSlice(a, &[_]i32{ 1, 2, 3 }) catch unreachable; + testing.expect(list.items.len == 12); + testing.expect(list.pop() == 3); + testing.expect(list.pop() == 2); + testing.expect(list.pop() == 1); + testing.expect(list.items.len == 9); + + list.appendSlice(a, &[_]i32{}) catch unreachable; + testing.expect(list.items.len == 9); + + // can only set on indices < self.items.len + list.items[7] = 33; + list.items[8] = 42; + + testing.expect(list.pop() == 42); + testing.expect(list.pop() == 33); + } +} + +test "std.ArrayList/ArrayListUnmanaged.appendNTimes" { + const a = testing.allocator; + { + var list = ArrayList(i32).init(a); + defer list.deinit(); + + try list.appendNTimes(2, 10); + testing.expectEqual(@as(usize, 10), list.items.len); + for (list.items) |element| { + testing.expectEqual(@as(i32, 2), element); } } + { + var list = ArrayListUnmanaged(i32){}; + defer list.deinit(a); - for (list.items) |v, i| { - testing.expect(v == @intCast(i32, i + 1)); - } - - testing.expect(list.pop() == 10); - testing.expect(list.items.len == 9); - - list.appendSlice(&[_]i32{ 1, 2, 3 }) catch unreachable; - testing.expect(list.items.len == 12); - testing.expect(list.pop() == 3); - testing.expect(list.pop() == 2); - testing.expect(list.pop() == 1); - testing.expect(list.items.len == 9); - - list.appendSlice(&[_]i32{}) catch unreachable; - testing.expect(list.items.len == 9); - - // can only set on indices < self.items.len - list.items[7] = 33; - list.items[8] = 42; - - testing.expect(list.pop() == 42); - testing.expect(list.pop() == 33); -} - -test "std.ArrayList.appendNTimes" { - var list = ArrayList(i32).init(testing.allocator); - defer list.deinit(); - - try list.appendNTimes(2, 10); - testing.expectEqual(@as(usize, 10), list.items.len); - for (list.items) |element| { - testing.expectEqual(@as(i32, 2), element); + try list.appendNTimes(a, 2, 10); + testing.expectEqual(@as(usize, 10), list.items.len); + for (list.items) |element| { + testing.expectEqual(@as(i32, 2), element); + } } } -test "std.ArrayList.appendNTimes with failing allocator" { - var list = ArrayList(i32).init(testing.failing_allocator); - defer list.deinit(); - testing.expectError(error.OutOfMemory, list.appendNTimes(2, 10)); +test "std.ArrayList/ArrayListUnmanaged.appendNTimes with failing allocator" { + const a = testing.failing_allocator; + { + var list = ArrayList(i32).init(a); + defer list.deinit(); + testing.expectError(error.OutOfMemory, list.appendNTimes(2, 10)); + } + { + var list = ArrayListUnmanaged(i32){}; + defer list.deinit(a); + testing.expectError(error.OutOfMemory, list.appendNTimes(a, 2, 10)); + } } -test "std.ArrayList.orderedRemove" { - var list = ArrayList(i32).init(testing.allocator); - defer list.deinit(); +test "std.ArrayList/ArrayListUnmanaged.orderedRemove" { + const a = testing.allocator; + { + var list = ArrayList(i32).init(a); + defer list.deinit(); - try list.append(1); - try list.append(2); - try list.append(3); - try list.append(4); - try list.append(5); - try list.append(6); - try list.append(7); + try list.append(1); + try list.append(2); + try list.append(3); + try list.append(4); + try list.append(5); + try list.append(6); + try list.append(7); - //remove from middle - testing.expectEqual(@as(i32, 4), list.orderedRemove(3)); - testing.expectEqual(@as(i32, 5), list.items[3]); - testing.expectEqual(@as(usize, 6), list.items.len); + //remove from middle + testing.expectEqual(@as(i32, 4), list.orderedRemove(3)); + testing.expectEqual(@as(i32, 5), list.items[3]); + testing.expectEqual(@as(usize, 6), list.items.len); - //remove from end - testing.expectEqual(@as(i32, 7), list.orderedRemove(5)); - testing.expectEqual(@as(usize, 5), list.items.len); + //remove from end + testing.expectEqual(@as(i32, 7), list.orderedRemove(5)); + testing.expectEqual(@as(usize, 5), list.items.len); - //remove from front - testing.expectEqual(@as(i32, 1), list.orderedRemove(0)); - testing.expectEqual(@as(i32, 2), list.items[0]); - testing.expectEqual(@as(usize, 4), list.items.len); + //remove from front + testing.expectEqual(@as(i32, 1), list.orderedRemove(0)); + testing.expectEqual(@as(i32, 2), list.items[0]); + testing.expectEqual(@as(usize, 4), list.items.len); + } + { + var list = ArrayListUnmanaged(i32){}; + defer list.deinit(a); + + try list.append(a, 1); + try list.append(a, 2); + try list.append(a, 3); + try list.append(a, 4); + try list.append(a, 5); + try list.append(a, 6); + try list.append(a, 7); + + //remove from middle + testing.expectEqual(@as(i32, 4), list.orderedRemove(3)); + testing.expectEqual(@as(i32, 5), list.items[3]); + testing.expectEqual(@as(usize, 6), list.items.len); + + //remove from end + testing.expectEqual(@as(i32, 7), list.orderedRemove(5)); + testing.expectEqual(@as(usize, 5), list.items.len); + + //remove from front + testing.expectEqual(@as(i32, 1), list.orderedRemove(0)); + testing.expectEqual(@as(i32, 2), list.items[0]); + testing.expectEqual(@as(usize, 4), list.items.len); + } } -test "std.ArrayList.swapRemove" { - var list = ArrayList(i32).init(testing.allocator); - defer list.deinit(); +test "std.ArrayList/ArrayListUnmanaged.swapRemove" { + const a = testing.allocator; + { + var list = ArrayList(i32).init(a); + defer list.deinit(); - try list.append(1); - try list.append(2); - try list.append(3); - try list.append(4); - try list.append(5); - try list.append(6); - try list.append(7); + try list.append(1); + try list.append(2); + try list.append(3); + try list.append(4); + try list.append(5); + try list.append(6); + try list.append(7); - //remove from middle - testing.expect(list.swapRemove(3) == 4); - testing.expect(list.items[3] == 7); - testing.expect(list.items.len == 6); + //remove from middle + testing.expect(list.swapRemove(3) == 4); + testing.expect(list.items[3] == 7); + testing.expect(list.items.len == 6); - //remove from end - testing.expect(list.swapRemove(5) == 6); - testing.expect(list.items.len == 5); + //remove from end + testing.expect(list.swapRemove(5) == 6); + testing.expect(list.items.len == 5); - //remove from front - testing.expect(list.swapRemove(0) == 1); - testing.expect(list.items[0] == 5); - testing.expect(list.items.len == 4); + //remove from front + testing.expect(list.swapRemove(0) == 1); + testing.expect(list.items[0] == 5); + testing.expect(list.items.len == 4); + } + { + var list = ArrayListUnmanaged(i32){}; + defer list.deinit(a); + + try list.append(a, 1); + try list.append(a, 2); + try list.append(a, 3); + try list.append(a, 4); + try list.append(a, 5); + try list.append(a, 6); + try list.append(a, 7); + + //remove from middle + testing.expect(list.swapRemove(3) == 4); + testing.expect(list.items[3] == 7); + testing.expect(list.items.len == 6); + + //remove from end + testing.expect(list.swapRemove(5) == 6); + testing.expect(list.items.len == 5); + + //remove from front + testing.expect(list.swapRemove(0) == 1); + testing.expect(list.items[0] == 5); + testing.expect(list.items.len == 4); + } } -test "std.ArrayList.insert" { - var list = ArrayList(i32).init(testing.allocator); - defer list.deinit(); +test "std.ArrayList/ArrayListUnmanaged.insert" { + const a = testing.allocator; + { + var list = ArrayList(i32).init(a); + defer list.deinit(); - try list.append(1); - try list.append(2); - try list.append(3); - try list.insert(0, 5); - testing.expect(list.items[0] == 5); - testing.expect(list.items[1] == 1); - testing.expect(list.items[2] == 2); - testing.expect(list.items[3] == 3); + try list.append(1); + try list.append(2); + try list.append(3); + try list.insert(0, 5); + testing.expect(list.items[0] == 5); + testing.expect(list.items[1] == 1); + testing.expect(list.items[2] == 2); + testing.expect(list.items[3] == 3); + } + { + var list = ArrayListUnmanaged(i32){}; + defer list.deinit(a); + + try list.append(a, 1); + try list.append(a, 2); + try list.append(a, 3); + try list.insert(a, 0, 5); + testing.expect(list.items[0] == 5); + testing.expect(list.items[1] == 1); + testing.expect(list.items[2] == 2); + testing.expect(list.items[3] == 3); + } } -test "std.ArrayList.insertSlice" { - var list = ArrayList(i32).init(testing.allocator); - defer list.deinit(); +test "std.ArrayList/ArrayListUnmanaged.insertSlice" { + const a = testing.allocator; + { + var list = ArrayList(i32).init(a); + defer list.deinit(); - try list.append(1); - try list.append(2); - try list.append(3); - try list.append(4); - try list.insertSlice(1, &[_]i32{ 9, 8 }); - testing.expect(list.items[0] == 1); - testing.expect(list.items[1] == 9); - testing.expect(list.items[2] == 8); - testing.expect(list.items[3] == 2); - testing.expect(list.items[4] == 3); - testing.expect(list.items[5] == 4); + try list.append(1); + try list.append(2); + try list.append(3); + try list.append(4); + try list.insertSlice(1, &[_]i32{ 9, 8 }); + testing.expect(list.items[0] == 1); + testing.expect(list.items[1] == 9); + testing.expect(list.items[2] == 8); + testing.expect(list.items[3] == 2); + testing.expect(list.items[4] == 3); + testing.expect(list.items[5] == 4); - const items = [_]i32{1}; - try list.insertSlice(0, items[0..0]); - testing.expect(list.items.len == 6); - testing.expect(list.items[0] == 1); + const items = [_]i32{1}; + try list.insertSlice(0, items[0..0]); + testing.expect(list.items.len == 6); + testing.expect(list.items[0] == 1); + } + { + var list = ArrayListUnmanaged(i32){}; + defer list.deinit(a); + + try list.append(a, 1); + try list.append(a, 2); + try list.append(a, 3); + try list.append(a, 4); + try list.insertSlice(a, 1, &[_]i32{ 9, 8 }); + testing.expect(list.items[0] == 1); + testing.expect(list.items[1] == 9); + testing.expect(list.items[2] == 8); + testing.expect(list.items[3] == 2); + testing.expect(list.items[4] == 3); + testing.expect(list.items[5] == 4); + + const items = [_]i32{1}; + try list.insertSlice(a, 0, items[0..0]); + testing.expect(list.items.len == 6); + testing.expect(list.items[0] == 1); + } } -test "std.ArrayList.replaceRange" { +test "std.ArrayList/ArrayListUnmanaged.replaceRange" { var arena = std.heap.ArenaAllocator.init(testing.allocator); defer arena.deinit(); + const a = &arena.allocator; - const alloc = &arena.allocator; const init = [_]i32{ 1, 2, 3, 4, 5 }; const new = [_]i32{ 0, 0, 0 }; - var list_zero = ArrayList(i32).init(alloc); - var list_eq = ArrayList(i32).init(alloc); - var list_lt = ArrayList(i32).init(alloc); - var list_gt = ArrayList(i32).init(alloc); + const result_zero = [_]i32{ 1, 0, 0, 0, 2, 3, 4, 5 }; + const result_eq = [_]i32{ 1, 0, 0, 0, 5 }; + const result_le = [_]i32{ 1, 0, 0, 0, 4, 5 }; + const result_gt = [_]i32{ 1, 0, 0, 0 }; - try list_zero.appendSlice(&init); - try list_eq.appendSlice(&init); - try list_lt.appendSlice(&init); - try list_gt.appendSlice(&init); + { + var list_zero = ArrayList(i32).init(a); + var list_eq = ArrayList(i32).init(a); + var list_lt = ArrayList(i32).init(a); + var list_gt = ArrayList(i32).init(a); - try list_zero.replaceRange(1, 0, &new); - try list_eq.replaceRange(1, 3, &new); - try list_lt.replaceRange(1, 2, &new); + try list_zero.appendSlice(&init); + try list_eq.appendSlice(&init); + try list_lt.appendSlice(&init); + try list_gt.appendSlice(&init); - // after_range > new_items.len in function body - testing.expect(1 + 4 > new.len); - try list_gt.replaceRange(1, 4, &new); + try list_zero.replaceRange(1, 0, &new); + try list_eq.replaceRange(1, 3, &new); + try list_lt.replaceRange(1, 2, &new); - testing.expectEqualSlices(i32, list_zero.items, &[_]i32{ 1, 0, 0, 0, 2, 3, 4, 5 }); - testing.expectEqualSlices(i32, list_eq.items, &[_]i32{ 1, 0, 0, 0, 5 }); - testing.expectEqualSlices(i32, list_lt.items, &[_]i32{ 1, 0, 0, 0, 4, 5 }); - testing.expectEqualSlices(i32, list_gt.items, &[_]i32{ 1, 0, 0, 0 }); + // after_range > new_items.len in function body + testing.expect(1 + 4 > new.len); + try list_gt.replaceRange(1, 4, &new); + + testing.expectEqualSlices(i32, list_zero.items, &result_zero); + testing.expectEqualSlices(i32, list_eq.items, &result_eq); + testing.expectEqualSlices(i32, list_lt.items, &result_le); + testing.expectEqualSlices(i32, list_gt.items, &result_gt); + } + { + var list_zero = ArrayListUnmanaged(i32){}; + var list_eq = ArrayListUnmanaged(i32){}; + var list_lt = ArrayListUnmanaged(i32){}; + var list_gt = ArrayListUnmanaged(i32){}; + + try list_zero.appendSlice(a, &init); + try list_eq.appendSlice(a, &init); + try list_lt.appendSlice(a, &init); + try list_gt.appendSlice(a, &init); + + try list_zero.replaceRange(a, 1, 0, &new); + try list_eq.replaceRange(a, 1, 3, &new); + try list_lt.replaceRange(a, 1, 2, &new); + + // after_range > new_items.len in function body + testing.expect(1 + 4 > new.len); + try list_gt.replaceRange(a, 1, 4, &new); + + testing.expectEqualSlices(i32, list_zero.items, &result_zero); + testing.expectEqualSlices(i32, list_eq.items, &result_eq); + testing.expectEqualSlices(i32, list_lt.items, &result_le); + testing.expectEqualSlices(i32, list_gt.items, &result_gt); + } } const Item = struct { @@ -819,11 +1032,25 @@ const Item = struct { sub_items: ArrayList(Item), }; -test "std.ArrayList: ArrayList(T) of struct T" { - var root = Item{ .integer = 1, .sub_items = ArrayList(Item).init(testing.allocator) }; - defer root.sub_items.deinit(); - try root.sub_items.append(Item{ .integer = 42, .sub_items = ArrayList(Item).init(testing.allocator) }); - testing.expect(root.sub_items.items[0].integer == 42); +const ItemUnmanaged = struct { + integer: i32, + sub_items: ArrayListUnmanaged(ItemUnmanaged), +}; + +test "std.ArrayList/ArrayListUnmanaged: ArrayList(T) of struct T" { + const a = std.testing.allocator; + { + var root = Item{ .integer = 1, .sub_items = ArrayList(Item).init(a) }; + defer root.sub_items.deinit(); + try root.sub_items.append(Item{ .integer = 42, .sub_items = ArrayList(Item).init(a) }); + testing.expect(root.sub_items.items[0].integer == 42); + } + { + var root = ItemUnmanaged{ .integer = 1, .sub_items = ArrayListUnmanaged(ItemUnmanaged){} }; + defer root.sub_items.deinit(a); + try root.sub_items.append(a, ItemUnmanaged{ .integer = 42, .sub_items = ArrayListUnmanaged(ItemUnmanaged){} }); + testing.expect(root.sub_items.items[0].integer == 42); + } } test "std.ArrayList(u8) implements outStream" { @@ -837,19 +1064,32 @@ test "std.ArrayList(u8) implements outStream" { testing.expectEqualSlices(u8, "x: 42\ny: 1234\n", buffer.span()); } -test "std.ArrayList.shrink still sets length on error.OutOfMemory" { +test "std.ArrayList/ArrayListUnmanaged.shrink still sets length on error.OutOfMemory" { // use an arena allocator to make sure realloc returns error.OutOfMemory var arena = std.heap.ArenaAllocator.init(testing.allocator); defer arena.deinit(); + const a = &arena.allocator; - var list = ArrayList(i32).init(&arena.allocator); + { + var list = ArrayList(i32).init(a); - try list.append(1); - try list.append(2); - try list.append(3); + try list.append(1); + try list.append(2); + try list.append(3); - list.shrink(1); - testing.expect(list.items.len == 1); + list.shrink(1); + testing.expect(list.items.len == 1); + } + { + var list = ArrayListUnmanaged(i32){}; + + try list.append(a, 1); + try list.append(a, 2); + try list.append(a, 3); + + list.shrink(a, 1); + testing.expect(list.items.len == 1); + } } test "std.ArrayList.writer" { @@ -864,7 +1104,7 @@ test "std.ArrayList.writer" { testing.expectEqualSlices(u8, list.items, "abcdefg"); } -test "addManyAsArray" { +test "std.ArrayList/ArrayListUnmanaged.addManyAsArray" { const a = std.testing.allocator; { var list = ArrayList(u8).init(a); From 6eaba61ef57c54231eccfdda42ed0c4de2985f27 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Tue, 29 Sep 2020 12:48:05 +0200 Subject: [PATCH 05/55] std/crypto: implement the HKDF construction --- lib/std/crypto.zig | 5 +++ lib/std/crypto/hkdf.zig | 68 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 lib/std/crypto/hkdf.zig diff --git a/lib/std/crypto.zig b/lib/std/crypto.zig index fa69d51d4d..36915e014c 100644 --- a/lib/std/crypto.zig +++ b/lib/std/crypto.zig @@ -95,6 +95,11 @@ pub const stream = struct { pub const ChaCha20With64BitNonce = @import("crypto/chacha20.zig").ChaCha20With64BitNonce; }; +/// Key derivation functions. +pub const kdf = struct { + pub const hkdf = @import("crypto/hkdf.zig"); +}; + const std = @import("std.zig"); pub const randomBytes = std.os.getrandom; diff --git a/lib/std/crypto/hkdf.zig b/lib/std/crypto/hkdf.zig new file mode 100644 index 0000000000..cbe7fccebf --- /dev/null +++ b/lib/std/crypto/hkdf.zig @@ -0,0 +1,68 @@ +const std = @import("../std.zig"); +const assert = std.debug.assert; +const hmac = std.crypto.auth.hmac; +const mem = std.mem; + +/// HKDF-SHA256 +pub const HkdfSha256 = Hkdf(hmac.sha2.HmacSha256); + +/// HKDF-SHA512 +pub const HkdfSha512 = Hkdf(hmac.sha2.HmacSha512); + +/// The Hkdf construction takes some source of initial keying material and +/// derives one or more uniform keys from it. +pub fn Hkdf(comptime Hmac: type) type { + return struct { + pub const prk_length = Hmac.mac_length; + + /// Return a master key from a salt and initial keying material. + fn extract(salt: []const u8, ikm: []const u8) [Hmac.mac_length]u8 { + var prk: [Hmac.mac_length]u8 = undefined; + Hmac.create(&prk, ikm, salt); + return prk; + } + + /// Derive a subkey from a master key `prk` and a subkey description `ctx`. + fn expand(out: []u8, ctx: []const u8, prk: [Hmac.mac_length]u8) void { + assert(out.len < Hmac.mac_length * 255); // output size is too large for the Hkdf construction + var i: usize = 0; + var counter = [1]u8{1}; + while (i + Hmac.mac_length <= out.len) : (i += Hmac.mac_length) { + var st = Hmac.init(&prk); + if (i != 0) { + st.update(out[i - Hmac.mac_length ..][0..Hmac.mac_length]); + } + st.update(ctx); + st.update(&counter); + st.final(out[i..][0..Hmac.mac_length]); + counter[0] += 1; + } + const left = out.len % Hmac.mac_length; + if (left > 0) { + var st = Hmac.init(&prk); + if (i != 0) { + st.update(out[i - Hmac.mac_length ..][0..Hmac.mac_length]); + } + st.update(ctx); + st.update(&counter); + var tmp: [Hmac.mac_length]u8 = undefined; + st.final(tmp[0..Hmac.mac_length]); + mem.copy(u8, out[i..][0..left], tmp[0..left]); + } + } + }; +} + +const htest = @import("test.zig"); + +test "Hkdf" { + const ikm = [_]u8{0x0b} ** 22; + const salt = [_]u8{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c }; + const context = [_]u8{ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9 }; + const kdf = HkdfSha256; + const prk = kdf.extract(&salt, &ikm); + htest.assertEqual("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5", &prk); + var out: [42]u8 = undefined; + kdf.expand(&out, &context, prk); + htest.assertEqual("3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865", &out); +} From d75d6e7f774c6236eb11a5a6b0277561a3b42a22 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Tue, 29 Sep 2020 21:33:14 +0200 Subject: [PATCH 06/55] Remove unused var, sort std.crypto.* --- lib/std/crypto.zig | 90 ++++++++++++++++++++--------------------- lib/std/crypto/hkdf.zig | 2 - 2 files changed, 45 insertions(+), 47 deletions(-) diff --git a/lib/std/crypto.zig b/lib/std/crypto.zig index 36915e014c..36eca6700a 100644 --- a/lib/std/crypto.zig +++ b/lib/std/crypto.zig @@ -4,6 +4,48 @@ // The MIT license requires this copyright notice to be included in all copies // and substantial portions of the software. +/// Authenticated Encryption with Associated Data +pub const aead = struct { + const chacha20 = @import("crypto/chacha20.zig"); + + pub const Gimli = @import("crypto/gimli.zig").Aead; + pub const ChaCha20Poly1305 = chacha20.Chacha20Poly1305; + pub const XChaCha20Poly1305 = chacha20.XChacha20Poly1305; + pub const AEGIS128L = @import("crypto/aegis.zig").AEGIS128L; + pub const AEGIS256 = @import("crypto/aegis.zig").AEGIS256; +}; + +/// Authentication (MAC) functions. +pub const auth = struct { + pub const hmac = @import("crypto/hmac.zig"); + pub const siphash = @import("crypto/siphash.zig"); +}; + +/// Core functions, that should rarely be used directly by applications. +pub const core = struct { + pub const aes = @import("crypto/aes.zig"); + pub const Gimli = @import("crypto/gimli.zig").State; + + /// Modes are generic compositions to construct encryption/decryption functions from block ciphers and permutations. + /// + /// These modes are designed to be building blocks for higher-level constructions, and should generally not be used directly by applications, as they may not provide the expected properties and security guarantees. + /// + /// Most applications may want to use AEADs instead. + pub const modes = @import("crypto/modes.zig"); +}; + +/// Diffie-Hellman key exchange functions. +pub const dh = struct { + pub const X25519 = @import("crypto/25519/x25519.zig").X25519; +}; + +/// Elliptic-curve arithmetic. +pub const ecc = struct { + pub const Curve25519 = @import("crypto/25519/curve25519.zig").Curve25519; + pub const Edwards25519 = @import("crypto/25519/edwards25519.zig").Edwards25519; + pub const Ristretto255 = @import("crypto/25519/ristretto255.zig").Ristretto255; +}; + /// Hash functions. pub const hash = struct { pub const Md5 = @import("crypto/md5.zig").Md5; @@ -15,21 +57,9 @@ pub const hash = struct { pub const Gimli = @import("crypto/gimli.zig").Hash; }; -/// Authentication (MAC) functions. -pub const auth = struct { - pub const hmac = @import("crypto/hmac.zig"); - pub const siphash = @import("crypto/siphash.zig"); -}; - -/// Authenticated Encryption with Associated Data -pub const aead = struct { - const chacha20 = @import("crypto/chacha20.zig"); - - pub const Gimli = @import("crypto/gimli.zig").Aead; - pub const ChaCha20Poly1305 = chacha20.Chacha20Poly1305; - pub const XChaCha20Poly1305 = chacha20.XChacha20Poly1305; - pub const AEGIS128L = @import("crypto/aegis.zig").AEGIS128L; - pub const AEGIS256 = @import("crypto/aegis.zig").AEGIS256; +/// Key derivation functions. +pub const kdf = struct { + pub const hkdf = @import("crypto/hkdf.zig"); }; /// MAC functions requiring single-use secret keys. @@ -57,31 +87,6 @@ pub const pwhash = struct { pub const pbkdf2 = @import("crypto/pbkdf2.zig").pbkdf2; }; -/// Core functions, that should rarely be used directly by applications. -pub const core = struct { - pub const aes = @import("crypto/aes.zig"); - pub const Gimli = @import("crypto/gimli.zig").State; - - /// Modes are generic compositions to construct encryption/decryption functions from block ciphers and permutations. - /// - /// These modes are designed to be building blocks for higher-level constructions, and should generally not be used directly by applications, as they may not provide the expected properties and security guarantees. - /// - /// Most applications may want to use AEADs instead. - pub const modes = @import("crypto/modes.zig"); -}; - -/// Elliptic-curve arithmetic. -pub const ecc = struct { - pub const Curve25519 = @import("crypto/25519/curve25519.zig").Curve25519; - pub const Edwards25519 = @import("crypto/25519/edwards25519.zig").Edwards25519; - pub const Ristretto255 = @import("crypto/25519/ristretto255.zig").Ristretto255; -}; - -/// Diffie-Hellman key exchange functions. -pub const dh = struct { - pub const X25519 = @import("crypto/25519/x25519.zig").X25519; -}; - /// Digital signature functions. pub const sign = struct { pub const Ed25519 = @import("crypto/25519/ed25519.zig").Ed25519; @@ -95,11 +100,6 @@ pub const stream = struct { pub const ChaCha20With64BitNonce = @import("crypto/chacha20.zig").ChaCha20With64BitNonce; }; -/// Key derivation functions. -pub const kdf = struct { - pub const hkdf = @import("crypto/hkdf.zig"); -}; - const std = @import("std.zig"); pub const randomBytes = std.os.getrandom; diff --git a/lib/std/crypto/hkdf.zig b/lib/std/crypto/hkdf.zig index cbe7fccebf..7ac3603637 100644 --- a/lib/std/crypto/hkdf.zig +++ b/lib/std/crypto/hkdf.zig @@ -13,8 +13,6 @@ pub const HkdfSha512 = Hkdf(hmac.sha2.HmacSha512); /// derives one or more uniform keys from it. pub fn Hkdf(comptime Hmac: type) type { return struct { - pub const prk_length = Hmac.mac_length; - /// Return a master key from a salt and initial keying material. fn extract(salt: []const u8, ikm: []const u8) [Hmac.mac_length]u8 { var prk: [Hmac.mac_length]u8 = undefined; From e903b00eecba34295da5490a90eb87aeb984d155 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Tue, 29 Sep 2020 14:01:20 -0600 Subject: [PATCH 07/55] stage1: Fix @Type(.Enum) with invalid tag_type Fixes https://github.com/ziglang/zig/issues/6459 --- src/stage1/ir.cpp | 7 +++++++ test/compile_errors.zig | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp index bb4ca8dbf3..7de4b923ba 100644 --- a/src/stage1/ir.cpp +++ b/src/stage1/ir.cpp @@ -26150,6 +26150,13 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI ContainerLayout layout = (ContainerLayout)bigint_as_u32(&layout_value->data.x_enum_tag); ZigType *tag_type = get_const_field_meta_type(ira, source_instr->source_node, payload, "tag_type", 1); + if (type_is_invalid(tag_type)) + return ira->codegen->invalid_inst_gen->value->type; + if (tag_type->id != ZigTypeIdInt) { + ir_add_error(ira, source_instr, buf_sprintf( + "TypeInfo.Enum.tag_type must be an integer type, not '%s'", buf_ptr(&tag_type->name))); + return ira->codegen->invalid_inst_gen->value->type; + } ZigValue *fields_value = get_const_field(ira, source_instr->source_node, payload, "fields", 2); if (fields_value == nullptr) diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 7a33de4f19..7c3fa544b6 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2,6 +2,42 @@ const tests = @import("tests.zig"); const std = @import("std"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add("@Type for exhaustive enum with undefined tag type", + \\const TypeInfo = @import("builtin").TypeInfo; + \\const Tag = @Type(.{ + \\ .Enum = .{ + \\ .layout = .Auto, + \\ .tag_type = undefined, + \\ .fields = &[_]TypeInfo.EnumField{}, + \\ .decls = &[_]TypeInfo.Declaration{}, + \\ .is_exhaustive = false, + \\ }, + \\}); + \\export fn entry() void { + \\ _ = @intToEnum(Tag, 0); + \\} + , &[_][]const u8{ + "tmp.zig:2:20: error: use of undefined value here causes undefined behavior", + }); + + cases.add("@Type for exhaustive enum with non-integer tag type", + \\const TypeInfo = @import("builtin").TypeInfo; + \\const Tag = @Type(.{ + \\ .Enum = .{ + \\ .layout = .Auto, + \\ .tag_type = bool, + \\ .fields = &[_]TypeInfo.EnumField{}, + \\ .decls = &[_]TypeInfo.Declaration{}, + \\ .is_exhaustive = false, + \\ }, + \\}); + \\export fn entry() void { + \\ _ = @intToEnum(Tag, 0); + \\} + , &[_][]const u8{ + "tmp.zig:2:20: error: TypeInfo.Enum.tag_type must be an integer type, not 'bool'", + }); + cases.add("slice sentinel mismatch", \\export fn entry() void { \\ const x = @import("std").meta.Vector(3, f32){ 25, 75, 5, 0 }; From 718a659773776de47e8ce6ba80da663539572056 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 30 Sep 2020 12:35:09 -0700 Subject: [PATCH 08/55] std: skip some tests that stage1 leaks too much memory with We can restore these when we have self-hosted available. This is intended to address #6467 --- lib/std/packed_int_array.zig | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/std/packed_int_array.zig b/lib/std/packed_int_array.zig index de99afa303..f25ff0b1b8 100644 --- a/lib/std/packed_int_array.zig +++ b/lib/std/packed_int_array.zig @@ -318,9 +318,12 @@ pub fn PackedIntSliceEndian(comptime Int: type, comptime endian: builtin.Endian) }; } +const we_are_testing_this_with_stage1_which_leaks_comptime_memory = true; + test "PackedIntArray" { // TODO @setEvalBranchQuota generates panics in wasm32. Investigate. if (builtin.arch == .wasm32) return error.SkipZigTest; + if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest; @setEvalBranchQuota(10000); const max_bits = 256; @@ -358,6 +361,7 @@ test "PackedIntArray" { } test "PackedIntArray init" { + if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest; const PackedArray = PackedIntArray(u3, 8); var packed_array = PackedArray.init([_]u3{ 0, 1, 2, 3, 4, 5, 6, 7 }); var i = @as(usize, 0); @@ -367,6 +371,7 @@ test "PackedIntArray init" { test "PackedIntSlice" { // TODO @setEvalBranchQuota generates panics in wasm32. Investigate. if (builtin.arch == .wasm32) return error.SkipZigTest; + if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest; @setEvalBranchQuota(10000); const max_bits = 256; @@ -405,6 +410,7 @@ test "PackedIntSlice" { } test "PackedIntSlice of PackedInt(Array/Slice)" { + if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest; const max_bits = 16; const int_count = 19; @@ -470,6 +476,7 @@ test "PackedIntSlice of PackedInt(Array/Slice)" { } test "PackedIntSlice accumulating bit offsets" { + if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest; //bit_offset is u3, so standard debugging asserts should catch // anything { @@ -497,6 +504,8 @@ test "PackedIntSlice accumulating bit offsets" { //@NOTE: As I do not have a big endian system to test this on, // big endian values were not tested test "PackedInt(Array/Slice) sliceCast" { + if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest; + const PackedArray = PackedIntArray(u1, 16); var packed_array = PackedArray.init([_]u1{ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 }); const packed_slice_cast_2 = packed_array.sliceCast(u2); @@ -537,6 +546,8 @@ test "PackedInt(Array/Slice) sliceCast" { } test "PackedInt(Array/Slice)Endian" { + if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest; + { const PackedArrayBe = PackedIntArrayEndian(u4, .Big, 8); var packed_array_be = PackedArrayBe.init([_]u4{ 0, 1, 2, 3, 4, 5, 6, 7 }); @@ -604,6 +615,8 @@ test "PackedInt(Array/Slice)Endian" { // after this one is not mapped and will cause a segfault if we // don't account for the bounds. test "PackedIntArray at end of available memory" { + if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest; + switch (builtin.os.tag) { .linux, .macosx, .ios, .freebsd, .netbsd, .windows => {}, else => return, @@ -623,6 +636,8 @@ test "PackedIntArray at end of available memory" { } test "PackedIntSlice at end of available memory" { + if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest; + switch (builtin.os.tag) { .linux, .macosx, .ios, .freebsd, .netbsd, .windows => {}, else => return, From 58873ed3f90325cee5c442169d609d02c71fd05a Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 30 Sep 2020 01:12:37 +0200 Subject: [PATCH 09/55] std/crypto: add GHASH implementation GHASH is required to implement AES-GCM. Optimized implementations for CPUs with instructions for carry-less multiplication will be added next. --- lib/std/crypto.zig | 1 + lib/std/crypto/benchmark.zig | 1 + lib/std/crypto/ghash.zig | 195 +++++++++++++++++++++++++++++++++++ 3 files changed, 197 insertions(+) create mode 100644 lib/std/crypto/ghash.zig diff --git a/lib/std/crypto.zig b/lib/std/crypto.zig index fa69d51d4d..5070305633 100644 --- a/lib/std/crypto.zig +++ b/lib/std/crypto.zig @@ -35,6 +35,7 @@ pub const aead = struct { /// MAC functions requiring single-use secret keys. pub const onetimeauth = struct { pub const Poly1305 = @import("crypto/poly1305.zig").Poly1305; + pub const Ghash = @import("crypto/ghash.zig").Ghash; }; /// A password hashing function derives a uniform key from low-entropy input material such as passwords. diff --git a/lib/std/crypto/benchmark.zig b/lib/std/crypto/benchmark.zig index 3c7e3445a2..d0ff29e896 100644 --- a/lib/std/crypto/benchmark.zig +++ b/lib/std/crypto/benchmark.zig @@ -57,6 +57,7 @@ pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64 } const macs = [_]Crypto{ + Crypto{ .ty = crypto.onetimeauth.Ghash, .name = "ghash" }, Crypto{ .ty = crypto.onetimeauth.Poly1305, .name = "poly1305" }, Crypto{ .ty = crypto.auth.hmac.HmacMd5, .name = "hmac-md5" }, Crypto{ .ty = crypto.auth.hmac.HmacSha1, .name = "hmac-sha1" }, diff --git a/lib/std/crypto/ghash.zig b/lib/std/crypto/ghash.zig new file mode 100644 index 0000000000..f05b5d7139 --- /dev/null +++ b/lib/std/crypto/ghash.zig @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. +// +// Adapted from BearSSL's ctmul64 implementation originally written by Thomas Pornin + +const std = @import("../std.zig"); +const assert = std.debug.assert; +const math = std.math; +const mem = std.mem; + +/// GHASH is a universal hash function that features multiplication +/// by a fixed parameter within a Galois field. +/// +/// It is not a general purpose hash function - The key must be secret, unpredictable and never reused. +/// +/// GHASH is typically used to compute the authentication tag in the AES-GCM construction. +pub const Ghash = struct { + pub const block_size: usize = 16; + pub const mac_length = 16; + pub const minimum_key_length = 16; + + y0: u64 = 0, + y1: u64 = 0, + h0: u64, + h1: u64, + h2: u64, + h0r: u64, + h1r: u64, + h2r: u64, + + leftover: usize = 0, + buf: [block_size]u8 align(16) = undefined, + + pub fn init(key: []const u8) Ghash { + assert(key.len >= minimum_key_length); + const h1 = mem.readIntBig(u64, key[0..8]); + const h0 = mem.readIntBig(u64, key[8..16]); + const h1r = @bitReverse(u64, h1); + const h0r = @bitReverse(u64, h0); + const h2 = h0 ^ h1; + const h2r = h0r ^ h1r; + + return Ghash{ + .h0 = h0, + .h1 = h1, + .h2 = h2, + .h0r = h0r, + .h1r = h1r, + .h2r = h2r, + }; + } + + fn bmul(x: u64, y: u64) u64 { + const x0 = x & 0x1111111111111111; + const x1 = x & 0x2222222222222222; + const x2 = x & 0x4444444444444444; + const x3 = x & 0x8888888888888888; + const y0 = y & 0x1111111111111111; + const y1 = y & 0x2222222222222222; + const y2 = y & 0x4444444444444444; + const y3 = y & 0x8888888888888888; + var z0 = (x0 *% y0) ^ (x1 *% y3) ^ (x2 *% y2) ^ (x3 *% y1); + var z1 = (x0 *% y1) ^ (x1 *% y0) ^ (x2 *% y3) ^ (x3 *% y2); + var z2 = (x0 *% y2) ^ (x1 *% y1) ^ (x2 *% y0) ^ (x3 *% y3); + var z3 = (x0 *% y3) ^ (x1 *% y2) ^ (x2 *% y1) ^ (x3 *% y0); + z0 &= 0x1111111111111111; + z1 &= 0x2222222222222222; + z2 &= 0x4444444444444444; + z3 &= 0x8888888888888888; + + return z0 | z1 | z2 | z3; + } + + fn blocks(st: *Ghash, msg: []const u8) void { + assert(msg.len % 16 == 0); // GHASH blocks() expects full blocks + var y1 = st.y1; + var y0 = st.y0; + + var i: usize = 0; + while (i + 16 <= msg.len) : (i += 16) { + y1 ^= mem.readIntBig(u64, msg[i..][0..8]); + y0 ^= mem.readIntBig(u64, msg[i..][8..16]); + + const y1r = @bitReverse(u64, y1); + const y0r = @bitReverse(u64, y0); + const y2 = y0 ^ y1; + const y2r = y0r ^ y1r; + + const z0 = bmul(y0, st.h0); + const z1 = bmul(y1, st.h1); + var z2 = bmul(y2, st.h2); + var z0h = bmul(y0r, st.h0r); + var z1h = bmul(y1r, st.h1r); + var z2h = bmul(y2r, st.h2r); + z2 ^= z0 ^ z1; + z2h ^= z0h ^ z1h; + z0h = @bitReverse(u64, z0h) >> 1; + z1h = @bitReverse(u64, z1h) >> 1; + z2h = @bitReverse(u64, z2h) >> 1; + + var v3 = z1h; + var v2 = z1 ^ z2h; + var v1 = z0h ^ z2; + var v0 = z0; + + v3 = (v3 << 1) | (v2 >> 63); + v2 = (v2 << 1) | (v1 >> 63); + v1 = (v1 << 1) | (v0 >> 63); + v0 = (v0 << 1); + + v2 ^= v0 ^ (v0 >> 1) ^ (v0 >> 2) ^ (v0 >> 7); + v1 ^= (v0 << 63) ^ (v0 << 62) ^ (v0 << 57); + y1 = v3 ^ v1 ^ (v1 >> 1) ^ (v1 >> 2) ^ (v1 >> 7); + y0 = v2 ^ (v1 << 63) ^ (v1 << 62) ^ (v1 << 57); + } + st.y1 = y1; + st.y0 = y0; + } + + pub fn update(st: *Ghash, m: []const u8) void { + var mb = m; + + if (st.leftover > 0) { + const want = math.min(block_size - st.leftover, mb.len); + const mc = mb[0..want]; + for (mc) |x, i| { + st.buf[st.leftover + i] = x; + } + mb = mb[want..]; + st.leftover += want; + if (st.leftover > block_size) { + return; + } + st.blocks(&st.buf); + st.leftover = 0; + } + if (mb.len >= block_size) { + const want = mb.len & ~(block_size - 1); + st.blocks(mb[0..want]); + mb = mb[want..]; + } + if (mb.len > 0) { + for (mb) |x, i| { + st.buf[st.leftover + i] = x; + } + st.leftover += mb.len; + } + } + + pub fn final(st: *Ghash, out: []u8) void { + assert(out.len >= mac_length); + if (st.leftover > 0) { + var i = st.leftover; + while (i < block_size) : (i += 1) { + st.buf[i] = 0; + } + st.blocks(&st.buf); + } + mem.writeIntBig(u64, out[0..8], st.y1); + mem.writeIntBig(u64, out[8..16], st.y0); + + mem.secureZero(u8, @ptrCast([*]u8, st)[0..@sizeOf(Ghash)]); + } + + pub fn create(out: []u8, msg: []const u8, key: []const u8) void { + std.debug.assert(out.len >= mac_length); + std.debug.assert(key.len >= minimum_key_length); + + var st = Ghash.init(key); + st.update(msg); + st.final(out); + } +}; + +const htest = @import("test.zig"); + +test "ghash" { + const key = [_]u8{0x42} ** 16; + const m = [_]u8{0x69} ** 256; + + var st = Ghash.init(&key); + st.update(&m); + var out: [16]u8 = undefined; + st.final(&out); + htest.assertEqual("889295fa746e8b174bf4ec80a65dea41", &out); + + st = Ghash.init(&key); + st.update(m[0..100]); + st.update(m[100..]); + st.final(&out); + htest.assertEqual("889295fa746e8b174bf4ec80a65dea41", &out); +} From f1ad94437baaae40109f388a7d44d698c10a56d3 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 30 Sep 2020 18:36:31 +0200 Subject: [PATCH 10/55] ghash & poly1305: use pointer to slices for keys and output --- lib/std/crypto/ghash.zig | 11 +++-------- lib/std/crypto/poly1305.zig | 11 +++-------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/lib/std/crypto/ghash.zig b/lib/std/crypto/ghash.zig index f05b5d7139..a7a6be9722 100644 --- a/lib/std/crypto/ghash.zig +++ b/lib/std/crypto/ghash.zig @@ -34,8 +34,7 @@ pub const Ghash = struct { leftover: usize = 0, buf: [block_size]u8 align(16) = undefined, - pub fn init(key: []const u8) Ghash { - assert(key.len >= minimum_key_length); + pub fn init(key: *const [minimum_key_length]u8) Ghash { const h1 = mem.readIntBig(u64, key[0..8]); const h0 = mem.readIntBig(u64, key[8..16]); const h1r = @bitReverse(u64, h1); @@ -150,8 +149,7 @@ pub const Ghash = struct { } } - pub fn final(st: *Ghash, out: []u8) void { - assert(out.len >= mac_length); + pub fn final(st: *Ghash, out: *[mac_length]u8) void { if (st.leftover > 0) { var i = st.leftover; while (i < block_size) : (i += 1) { @@ -165,10 +163,7 @@ pub const Ghash = struct { mem.secureZero(u8, @ptrCast([*]u8, st)[0..@sizeOf(Ghash)]); } - pub fn create(out: []u8, msg: []const u8, key: []const u8) void { - std.debug.assert(out.len >= mac_length); - std.debug.assert(key.len >= minimum_key_length); - + pub fn create(out: *[mac_length]u8, msg: []const u8, key: *const [minimum_key_length]u8) void { var st = Ghash.init(key); st.update(msg); st.final(out); diff --git a/lib/std/crypto/poly1305.zig b/lib/std/crypto/poly1305.zig index a95b9d7cb3..31d1d6ba5a 100644 --- a/lib/std/crypto/poly1305.zig +++ b/lib/std/crypto/poly1305.zig @@ -22,8 +22,7 @@ pub const Poly1305 = struct { // partial block buffer buf: [block_size]u8 align(16) = undefined, - pub fn init(key: []const u8) Poly1305 { - std.debug.assert(key.len >= minimum_key_length); + pub fn init(key: *const [minimum_key_length]u8) Poly1305 { const t0 = mem.readIntLittle(u64, key[0..8]); const t1 = mem.readIntLittle(u64, key[8..16]); return Poly1305{ @@ -115,8 +114,7 @@ pub const Poly1305 = struct { } } - pub fn final(st: *Poly1305, out: []u8) void { - std.debug.assert(out.len >= mac_length); + pub fn final(st: *Poly1305, out: *[mac_length]u8) void { if (st.leftover > 0) { var i = st.leftover; st.buf[i] = 1; @@ -187,10 +185,7 @@ pub const Poly1305 = struct { std.mem.secureZero(u8, @ptrCast([*]u8, st)[0..@sizeOf(Poly1305)]); } - pub fn create(out: []u8, msg: []const u8, key: []const u8) void { - std.debug.assert(out.len >= mac_length); - std.debug.assert(key.len >= minimum_key_length); - + pub fn create(out: *[mac_length]u8, msg: []const u8, key: *const [minimum_key_length]u8) void { var st = Poly1305.init(key); st.update(msg); st.final(out); From 8161de7fa44393c08cf96c9f9aa5379f98925472 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 30 Sep 2020 22:34:17 +0200 Subject: [PATCH 11/55] Implement ghash aggregated reduction Performance increases from ~400 MiB/s to 450 MiB/s at the expense of extra code. Thus, aggregation is disabled on ReleaseSmall. Since the multiplication cost is significant compared to the reduction, aggregating more than 2 blocks is probably not worth it. --- lib/std/crypto/ghash.zig | 130 +++++++++++++++++++++++++++++++++++---- 1 file changed, 118 insertions(+), 12 deletions(-) diff --git a/lib/std/crypto/ghash.zig b/lib/std/crypto/ghash.zig index a7a6be9722..803547099f 100644 --- a/lib/std/crypto/ghash.zig +++ b/lib/std/crypto/ghash.zig @@ -31,6 +31,13 @@ pub const Ghash = struct { h1r: u64, h2r: u64, + hh0: u64 = undefined, + hh1: u64 = undefined, + hh2: u64 = undefined, + hh0r: u64 = undefined, + hh1r: u64 = undefined, + hh2r: u64 = undefined, + leftover: usize = 0, buf: [block_size]u8 align(16) = undefined, @@ -42,14 +49,49 @@ pub const Ghash = struct { const h2 = h0 ^ h1; const h2r = h0r ^ h1r; - return Ghash{ - .h0 = h0, - .h1 = h1, - .h2 = h2, - .h0r = h0r, - .h1r = h1r, - .h2r = h2r, - }; + if (std.builtin.mode == .ReleaseSmall) { + return Ghash{ + .h0 = h0, + .h1 = h1, + .h2 = h2, + .h0r = h0r, + .h1r = h1r, + .h2r = h2r, + }; + } else { + // Precompute H^2 + var hh = Ghash{ + .h0 = h0, + .h1 = h1, + .h2 = h2, + .h0r = h0r, + .h1r = h1r, + .h2r = h2r, + }; + hh.update(key); + const hh1 = hh.y1; + const hh0 = hh.y0; + const hh1r = @bitReverse(u64, hh1); + const hh0r = @bitReverse(u64, hh0); + const hh2 = hh0 ^ hh1; + const hh2r = hh0r ^ hh1r; + + return Ghash{ + .h0 = h0, + .h1 = h1, + .h2 = h2, + .h0r = h0r, + .h1r = h1r, + .h2r = h2r, + + .hh0 = hh0, + .hh1 = hh1, + .hh2 = hh2, + .hh0r = hh0r, + .hh1r = hh1r, + .hh2r = hh2r, + }; + } } fn bmul(x: u64, y: u64) u64 { @@ -79,6 +121,71 @@ pub const Ghash = struct { var y0 = st.y0; var i: usize = 0; + + // 2-blocks aggregated reduction + if (std.builtin.mode != .ReleaseSmall) { + while (i + 32 <= msg.len) : (i += 32) { + // B0 * H^2 unreduced + y1 ^= mem.readIntBig(u64, msg[i..][0..8]); + y0 ^= mem.readIntBig(u64, msg[i..][8..16]); + + const y1r = @bitReverse(u64, y1); + const y0r = @bitReverse(u64, y0); + const y2 = y0 ^ y1; + const y2r = y0r ^ y1r; + + var z0 = bmul(y0, st.hh0); + var z1 = bmul(y1, st.hh1); + var z2 = bmul(y2, st.hh2) ^ z0 ^ z1; + var z0h = bmul(y0r, st.hh0r); + var z1h = bmul(y1r, st.hh1r); + var z2h = bmul(y2r, st.hh2r) ^ z0h ^ z1h; + + // B1 * H unreduced + const sy1 = mem.readIntBig(u64, msg[i..][16..24]); + const sy0 = mem.readIntBig(u64, msg[i..][24..32]); + + const sy1r = @bitReverse(u64, sy1); + const sy0r = @bitReverse(u64, sy0); + const sy2 = sy0 ^ sy1; + const sy2r = sy0r ^ sy1r; + + const sz0 = bmul(sy0, st.h0); + const sz1 = bmul(sy1, st.h1); + const sz2 = bmul(sy2, st.h2) ^ sz0 ^ sz1; + const sz0h = bmul(sy0r, st.h0r); + const sz1h = bmul(sy1r, st.h1r); + const sz2h = bmul(sy2r, st.h2r) ^ sz0h ^ sz1h; + + // ((B0 * H^2) + B1 * H) (mod M) + z0 ^= sz0; + z1 ^= sz1; + z2 ^= sz2; + z0h ^= sz0h; + z1h ^= sz1h; + z2h ^= sz2h; + z0h = @bitReverse(u64, z0h) >> 1; + z1h = @bitReverse(u64, z1h) >> 1; + z2h = @bitReverse(u64, z2h) >> 1; + + var v3 = z1h; + var v2 = z1 ^ z2h; + var v1 = z0h ^ z2; + var v0 = z0; + + v3 = (v3 << 1) | (v2 >> 63); + v2 = (v2 << 1) | (v1 >> 63); + v1 = (v1 << 1) | (v0 >> 63); + v0 = (v0 << 1); + + v2 ^= v0 ^ (v0 >> 1) ^ (v0 >> 2) ^ (v0 >> 7); + v1 ^= (v0 << 63) ^ (v0 << 62) ^ (v0 << 57); + y1 = v3 ^ v1 ^ (v1 >> 1) ^ (v1 >> 2) ^ (v1 >> 7); + y0 = v2 ^ (v1 << 63) ^ (v1 << 62) ^ (v1 << 57); + } + } + + // single block while (i + 16 <= msg.len) : (i += 16) { y1 ^= mem.readIntBig(u64, msg[i..][0..8]); y0 ^= mem.readIntBig(u64, msg[i..][8..16]); @@ -90,16 +197,15 @@ pub const Ghash = struct { const z0 = bmul(y0, st.h0); const z1 = bmul(y1, st.h1); - var z2 = bmul(y2, st.h2); + var z2 = bmul(y2, st.h2) ^ z0 ^ z1; var z0h = bmul(y0r, st.h0r); var z1h = bmul(y1r, st.h1r); - var z2h = bmul(y2r, st.h2r); - z2 ^= z0 ^ z1; - z2h ^= z0h ^ z1h; + var z2h = bmul(y2r, st.h2r) ^ z0h ^ z1h; z0h = @bitReverse(u64, z0h) >> 1; z1h = @bitReverse(u64, z1h) >> 1; z2h = @bitReverse(u64, z2h) >> 1; + // shift & reduce var v3 = z1h; var v2 = z1 ^ z2h; var v1 = z0h ^ z2; From 97fd0974b9372f65c661908fb1ffc01d68255dae Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 1 Oct 2020 01:34:23 +0200 Subject: [PATCH 12/55] ghash: add pclmul support on x86_64 --- lib/std/crypto/ghash.zig | 54 +++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/lib/std/crypto/ghash.zig b/lib/std/crypto/ghash.zig index 803547099f..6a1bf7c186 100644 --- a/lib/std/crypto/ghash.zig +++ b/lib/std/crypto/ghash.zig @@ -94,7 +94,18 @@ pub const Ghash = struct { } } - fn bmul(x: u64, y: u64) u64 { + inline fn clmul_pclmul(x: u64, y: u64) u64 { + const Vector = std.meta.Vector; + const product = asm ( + \\ vpclmulqdq $0x00, %[x], %[y], %[out] + : [out] "=x" (-> Vector(2, u64)) + : [x] "x" (@bitCast(Vector(2, u64), @as(u128, x))), + [y] "x" (@bitCast(Vector(2, u64), @as(u128, y))) + ); + return product[0]; + } + + fn clmul_soft(x: u64, y: u64) u64 { const x0 = x & 0x1111111111111111; const x1 = x & 0x2222222222222222; const x2 = x & 0x4444444444444444; @@ -111,10 +122,13 @@ pub const Ghash = struct { z1 &= 0x2222222222222222; z2 &= 0x4444444444444444; z3 &= 0x8888888888888888; - return z0 | z1 | z2 | z3; } + const has_pclmul = comptime std.Target.x86.featureSetHas(std.Target.current.cpu.features, .pclmul); + const has_avx = comptime std.Target.x86.featureSetHas(std.Target.current.cpu.features, .avx); + const clmul = if (std.Target.current.cpu.arch == .x86_64 and has_pclmul and has_avx) clmul_pclmul else clmul_soft; + fn blocks(st: *Ghash, msg: []const u8) void { assert(msg.len % 16 == 0); // GHASH blocks() expects full blocks var y1 = st.y1; @@ -134,12 +148,12 @@ pub const Ghash = struct { const y2 = y0 ^ y1; const y2r = y0r ^ y1r; - var z0 = bmul(y0, st.hh0); - var z1 = bmul(y1, st.hh1); - var z2 = bmul(y2, st.hh2) ^ z0 ^ z1; - var z0h = bmul(y0r, st.hh0r); - var z1h = bmul(y1r, st.hh1r); - var z2h = bmul(y2r, st.hh2r) ^ z0h ^ z1h; + var z0 = clmul(y0, st.hh0); + var z1 = clmul(y1, st.hh1); + var z2 = clmul(y2, st.hh2) ^ z0 ^ z1; + var z0h = clmul(y0r, st.hh0r); + var z1h = clmul(y1r, st.hh1r); + var z2h = clmul(y2r, st.hh2r) ^ z0h ^ z1h; // B1 * H unreduced const sy1 = mem.readIntBig(u64, msg[i..][16..24]); @@ -150,12 +164,12 @@ pub const Ghash = struct { const sy2 = sy0 ^ sy1; const sy2r = sy0r ^ sy1r; - const sz0 = bmul(sy0, st.h0); - const sz1 = bmul(sy1, st.h1); - const sz2 = bmul(sy2, st.h2) ^ sz0 ^ sz1; - const sz0h = bmul(sy0r, st.h0r); - const sz1h = bmul(sy1r, st.h1r); - const sz2h = bmul(sy2r, st.h2r) ^ sz0h ^ sz1h; + const sz0 = clmul(sy0, st.h0); + const sz1 = clmul(sy1, st.h1); + const sz2 = clmul(sy2, st.h2) ^ sz0 ^ sz1; + const sz0h = clmul(sy0r, st.h0r); + const sz1h = clmul(sy1r, st.h1r); + const sz2h = clmul(sy2r, st.h2r) ^ sz0h ^ sz1h; // ((B0 * H^2) + B1 * H) (mod M) z0 ^= sz0; @@ -195,12 +209,12 @@ pub const Ghash = struct { const y2 = y0 ^ y1; const y2r = y0r ^ y1r; - const z0 = bmul(y0, st.h0); - const z1 = bmul(y1, st.h1); - var z2 = bmul(y2, st.h2) ^ z0 ^ z1; - var z0h = bmul(y0r, st.h0r); - var z1h = bmul(y1r, st.h1r); - var z2h = bmul(y2r, st.h2r) ^ z0h ^ z1h; + const z0 = clmul(y0, st.h0); + const z1 = clmul(y1, st.h1); + var z2 = clmul(y2, st.h2) ^ z0 ^ z1; + var z0h = clmul(y0r, st.h0r); + var z1h = clmul(y1r, st.h1r); + var z2h = clmul(y2r, st.h2r) ^ z0h ^ z1h; z0h = @bitReverse(u64, z0h) >> 1; z1h = @bitReverse(u64, z1h) >> 1; z2h = @bitReverse(u64, z2h) >> 1; From 2a3393eff853fe0a1dee766c859a345186e91fa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20=28xq=29=20Quei=C3=9Fner?= Date: Thu, 1 Oct 2020 09:40:03 +0200 Subject: [PATCH 13/55] Adds error return trace printing to stage1. --- src/stage1.zig | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/stage1.zig b/src/stage1.zig index a989ad4be3..10b85899c2 100644 --- a/src/stage1.zig +++ b/src/stage1.zig @@ -39,7 +39,12 @@ pub export fn main(argc: c_int, argv: [*]const [*:0]const u8) c_int { for (args) |*arg, i| { arg.* = mem.spanZ(argv[i]); } - stage2.mainArgs(gpa, arena, args) catch |err| fatal("{}", .{@errorName(err)}); + stage2.mainArgs(gpa, arena, args) catch |err| { + if (@errorReturnTrace()) |trace| { + std.debug.dumpStackTrace(trace.*); + } + fatal("unhandled internal error: {}", .{@errorName(err)}); + }; return 0; } From 1b2d50737a9cfd0af2e219db08aec66bdf259f2d Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Thu, 1 Oct 2020 11:27:59 +0200 Subject: [PATCH 14/55] mingw: Add user32.def for 32bit Windows Closes #6479 --- lib/libc/mingw/lib32/user32.def | 998 ++++++++++++++++++++++++++++++++ 1 file changed, 998 insertions(+) create mode 100644 lib/libc/mingw/lib32/user32.def diff --git a/lib/libc/mingw/lib32/user32.def b/lib/libc/mingw/lib32/user32.def new file mode 100644 index 0000000000..c20d16835a --- /dev/null +++ b/lib/libc/mingw/lib32/user32.def @@ -0,0 +1,998 @@ +LIBRARY USER32.dll +EXPORTS +;ord_1500@16 @1500 +;ord_1501@4 @1501 +;ord_1502@12 @1502 +ActivateKeyboardLayout@8 +AddClipboardFormatListener@4 +AdjustWindowRect@12 +AdjustWindowRectEx@16 +AlignRects@16 +AllowForegroundActivation@0 +AllowSetForegroundWindow@4 +AnimateWindow@12 +AnyPopup@0 +AppendMenuA@16 +AppendMenuW@16 +ArrangeIconicWindows@4 +AttachThreadInput@12 +BeginDeferWindowPos@4 +BeginPaint@8 +BlockInput@4 +BringWindowToTop@4 +BroadcastSystemMessage@20 +BroadcastSystemMessageA@20 +BroadcastSystemMessageExA@24 +BroadcastSystemMessageExW@24 +BroadcastSystemMessageW@20 +BuildReasonArray@12 +CalcChildScroll@8 +CalcMenuBar@20 +CalculatePopupWindowPosition@20 +CallMsgFilter@8 +CallMsgFilterA@8 +CallMsgFilterW@8 +CallNextHookEx@16 +CallWindowProcA@20 +CallWindowProcW@20 +CancelShutdown@0 +CascadeChildWindows@8 +CascadeWindows@20 +ChangeClipboardChain@8 +ChangeDisplaySettingsA@8 +ChangeDisplaySettingsExA@20 +ChangeDisplaySettingsExW@20 +ChangeDisplaySettingsW@8 +ChangeMenuA@20 +ChangeMenuW@20 +ChangeWindowMessageFilter@8 +ChangeWindowMessageFilterEx@16 +CharLowerA@4 +CharLowerBuffA@8 +CharLowerBuffW@8 +CharLowerW@4 +CharNextA@4 +;ord_1550@12 @1550 +;ord_1551@8 @1551 +;ord_1552@8 @1552 +;ord_1553@12 @1553 +;ord_1554@8 @1554 +;ord_1555@16 @1555 +;ord_1556@4 @1556 +CharNextExA@12 +CharNextW@4 +CharPrevA@8 +CharPrevExA@16 +CharPrevW@8 +CharToOemA@8 +CharToOemBuffA@12 +CharToOemBuffW@12 +CharToOemW@8 +CharUpperA@4 +CharUpperBuffA@8 +CharUpperBuffW@8 +CharUpperW@4 +CheckDesktopByThreadId@4 +CheckDBCSEnabledExt@0 +CheckDlgButton@12 +CheckMenuItem@12 +CheckMenuRadioItem@20 +CheckProcessForClipboardAccess@8 +CheckProcessSession@4 +CheckRadioButton@16 +CheckWindowThreadDesktop@8 +ChildWindowFromPoint@12 +ChildWindowFromPointEx@16 +CliImmSetHotKey@16 +ClientThreadSetup@0 +ClientToScreen@8 +ClipCursor@4 +CloseClipboard@0 +CloseDesktop@4 +CloseGestureInfoHandle@4 +CloseTouchInputHandle@4 +CloseWindow@4 +CloseWindowStation@4 +ConsoleControl@12 +ControlMagnification@8 +CopyAcceleratorTableA@12 +CopyAcceleratorTableW@12 +CopyIcon@4 +CopyImage@20 +CopyRect@8 +CountClipboardFormats@0 +CreateAcceleratorTableA@8 +CreateAcceleratorTableW@8 +CreateCaret@16 +CreateCursor@28 +CreateDCompositionHwndTarget@12 +CreateDesktopA@24 +CreateDesktopExA@32 +CreateDesktopExW@32 +CreateDesktopW@24 +CreateDialogIndirectParamA@20 +CreateDialogIndirectParamAorW@24 +CreateDialogIndirectParamW@20 +CreateDialogParamA@20 +CreateDialogParamW@20 +CreateIcon@28 +CreateIconFromResource@16 +CreateIconFromResourceEx@28 +CreateIconIndirect@4 +CreateMDIWindowA@40 +CreateMDIWindowW@40 +CreateMenu@0 +CreatePopupMenu@0 +CreateSystemThreads@16 ; ReactOS has the @8 variant +CreateWindowExA@48 +CreateWindowExW@48 +CreateWindowInBand@52 +CreateWindowIndirect@4 +CreateWindowStationA@16 +CreateWindowStationW@16 +CsrBroadcastSystemMessageExW@24 +CtxInitUser32@0 +DdeAbandonTransaction@12 +DdeAccessData@8 +DdeAddData@16 +DdeClientTransaction@32 +DdeCmpStringHandles@8 +DdeConnect@16 +DdeConnectList@20 +DdeCreateDataHandle@28 +DdeCreateStringHandleA@12 +DdeCreateStringHandleW@12 +DdeDisconnect@4 +DdeDisconnectList@4 +DdeEnableCallback@12 +DdeFreeDataHandle@4 +DdeFreeStringHandle@8 +DdeGetData@16 +DdeGetLastError@4 +DdeGetQualityOfService@12 +DdeImpersonateClient@4 +DdeInitializeA@16 +DdeInitializeW@16 +DdeKeepStringHandle@8 +DdeNameService@16 +DdePostAdvise@12 +DdeQueryConvInfo@12 +DdeQueryNextServer@8 +DdeQueryStringA@20 +DdeQueryStringW@20 +DdeReconnect@4 +DdeSetQualityOfService@12 +DdeSetUserHandle@12 +DdeUnaccessData@4 +DdeUninitialize@4 +DefDlgProcA@16 +DefDlgProcW@16 +DefFrameProcA@20 +DefFrameProcW@20 +DefMDIChildProcA@16 +DefMDIChildProcW@16 +DefRawInputProc@12 +DefWindowProcA@16 +DefWindowProcW@16 +DeferWindowPos@32 +DeferWindowPosAndBand@36 +DeleteMenu@12 +DeregisterShellHookWindow@4 +DestroyAcceleratorTable@4 +DestroyCaret@0 +DestroyCursor@4 +DestroyDCompositionHwndTarget@8 +DestroyIcon@4 +DestroyMenu@4 +DestroyReasons@4 +DestroyWindow@4 +DeviceEventWorker@24 ; No documentation whatsoever, ReactOS has a stub with @20 - https://www.reactos.org/archives/public/ros-diffs/2011-February/040308.html +DialogBoxIndirectParamA@20 +DialogBoxIndirectParamAorW@24 +DialogBoxIndirectParamW@20 +DialogBoxParamA@20 +DialogBoxParamW@20 +DisableProcessWindowsGhosting@0 +DispatchMessageA@4 +DispatchMessageW@4 +DisplayConfigGetDeviceInfo@4 +DisplayConfigSetDeviceInfo@4 +DisplayExitWindowsWarnings@4 +DlgDirListA@20 +DlgDirListComboBoxA@20 +DlgDirListComboBoxW@20 +DlgDirListW@20 +DlgDirSelectComboBoxExA@16 +DlgDirSelectComboBoxExW@16 +DlgDirSelectExA@16 +DlgDirSelectExW@16 +DoSoundConnect@0 +DoSoundDisconnect@0 +DragDetect@12 +DragObject@20 +DrawAnimatedRects@16 +DrawCaption@16 +DrawCaptionTempA@28 +DrawCaptionTempW@28 +DrawEdge@16 +DrawFocusRect@8 +DrawFrame@16 +DrawFrameControl@16 +DrawIcon@16 +DrawIconEx@36 +DrawMenuBar@4 +DrawMenuBarTemp@20 +DrawStateA@40 +DrawStateW@40 +DrawTextA@20 +DrawTextExA@24 +DrawTextExW@24 +DrawTextW@20 +DwmGetDxSharedSurface@24 +DwmGetRemoteSessionOcclusionEvent@0 +DwmGetRemoteSessionOcclusionState@0 +DwmLockScreenUpdates@4 +DwmStartRedirection@8 ; Mentioned on http://habrahabr.ru/post/145174/ , enables GDI virtualization (for security purposes) +DwmStopRedirection@0 +DwmValidateWindow@8 +EditWndProc@16 +EmptyClipboard@0 +EnableMenuItem@12 +EnableMouseInPointer@4 +EnableScrollBar@12 +EnableSessionForMMCSS@4 +EnableWindow@8 +EndDeferWindowPos@4 +EndDeferWindowPosEx@8 +EndDialog@8 +EndMenu@0 +EndPaint@8 +EndTask@12 +EnterReaderModeHelper@4 +EnumChildWindows@12 +EnumClipboardFormats@4 +EnumDesktopWindows@12 +EnumDesktopsA@12 +EnumDesktopsW@12 +EnumDisplayDevicesA@16 +EnumDisplayDevicesW@16 +EnumDisplayMonitors@16 +EnumDisplaySettingsA@12 +EnumDisplaySettingsExA@16 +EnumDisplaySettingsExW@16 +EnumDisplaySettingsW@12 +EnumPropsA@8 +EnumPropsExA@12 +EnumPropsExW@12 +EnumPropsW@8 +EnumThreadWindows@12 +EnumWindowStationsA@8 +EnumWindowStationsW@8 +EnumWindows@8 +EqualRect@8 +EvaluateProximityToPolygon@16 +EvaluateProximityToRect@12 +ExcludeUpdateRgn@8 +ExitWindowsEx@8 +FillRect@12 +FindWindowA@8 +FindWindowExA@16 +FindWindowExW@16 +FindWindowW@8 +FlashWindow@8 +FlashWindowEx@4 +FrameRect@12 +FreeDDElParam@8 +FrostCrashedWindow@8 +GetActiveWindow@0 +GetAltTabInfo@20 +GetAltTabInfoA@20 +GetAltTabInfoW@20 +GetAncestor@8 +GetAppCompatFlags2@4 +GetAppCompatFlags@8 ; ReactOS has @4 version http://doxygen.reactos.org/d9/d71/undocuser_8h_a9b76cdc68c523a061c86a40367049ed2.html +GetAsyncKeyState@4 +GetAutoRotationState@4 +GetCIMSSM@4 +GetCapture@0 +GetCaretBlinkTime@0 +GetCaretPos@4 +GetClassInfoA@12 +GetClassInfoExA@12 +GetClassInfoExW@12 +GetClassInfoW@12 +GetClassLongA@8 +GetClassLongW@8 +GetClassNameA@12 +GetClassNameW@12 +GetClassWord@8 +GetClientRect@8 +GetClipCursor@4 +GetClipboardAccessToken@8 +GetClipboardData@4 +GetClipboardFormatNameA@12 +GetClipboardFormatNameW@12 +GetClipboardOwner@0 +GetClipboardSequenceNumber@0 +GetClipboardViewer@0 +GetComboBoxInfo@8 +GetCurrentInputMessageSource@4 +GetCursor@0 +GetCursorFrameInfo@20 +GetCursorInfo@4 +GetCursorPos@4 +GetDC@4 +GetDCEx@12 +GetDesktopID@8 +GetDesktopWindow@0 +GetDialogBaseUnits@0 +GetDisplayAutoRotationPreferences@4 +GetDisplayConfigBufferSizes@12 +GetDlgCtrlID@4 +GetDlgItem@8 +GetDlgItemInt@16 +GetDlgItemTextA@16 +GetDlgItemTextW@16 +GetDoubleClickTime@0 +GetDpiForMonitorInternal@16 +GetFocus@0 +GetForegroundWindow@0 +GetGUIThreadInfo@8 +GetGestureConfig@24 +GetGestureExtraArgs@12 +GetGestureInfo@8 +GetGuiResources@8 +GetIconInfo@8 +GetIconInfoExA@8 +GetIconInfoExW@8 +GetInputDesktop@0 +GetInputLocaleInfo@8 +GetInputState@0 +GetInternalWindowPos@12 +GetKBCodePage@0 +GetKeyNameTextA@12 +GetKeyNameTextW@12 +GetKeyState@4 +GetKeyboardLayout@4 +GetKeyboardLayoutList@8 +GetKeyboardLayoutNameA@4 +GetKeyboardLayoutNameW@4 +GetKeyboardState@4 +GetKeyboardType@4 +GetLastActivePopup@4 +GetLastInputInfo@4 +GetLayeredWindowAttributes@16 +GetListBoxInfo@4 +GetMagnificationDesktopColorEffect@4 +GetMagnificationDesktopMagnification@12 +GetMagnificationLensCtxInformation@16 +GetMenu@4 +GetMenuBarInfo@16 +GetMenuCheckMarkDimensions@0 +GetMenuContextHelpId@4 +GetMenuDefaultItem@12 +GetMenuInfo@8 +GetMenuItemCount@4 +GetMenuItemID@8 +GetMenuItemInfoA@16 +GetMenuItemInfoW@16 +GetMenuItemRect@16 +GetMenuState@12 +GetMenuStringA@20 +GetMenuStringW@20 +GetMessageA@16 +GetMessageExtraInfo@0 +GetMessagePos@0 +GetMessageTime@0 +GetMessageW@16 +GetMonitorInfoA@8 +GetMonitorInfoW@8 +GetMouseMovePointsEx@20 +GetNextDlgGroupItem@12 +GetNextDlgTabItem@12 +GetOpenClipboardWindow@0 +GetParent@4 +GetPhysicalCursorPos@4 +GetPointerCursorId@8 +GetPointerDevice@8 +GetPointerDeviceCursors@12 +GetPointerDeviceProperties@12 +GetPointerDeviceRects@12 +GetPointerDevices@8 +GetPointerFrameInfo@12 +GetPointerFrameInfoHistory@16 +GetPointerFramePenInfo@12 +GetPointerFramePenInfoHistory@16 +GetPointerFrameTouchInfo@12 +GetPointerFrameTouchInfoHistory@16 +GetPointerInfo@8 +GetPointerInfoHistory@12 +GetPointerInputTransform@12 +GetPointerPenInfo@8 +GetPointerPenInfoHistory@12 +GetPointerTouchInfo@8 +GetPointerTouchInfoHistory@12 +GetPointerType@8 +GetPriorityClipboardFormat@8 +GetProcessDefaultLayout@4 +GetProcessDpiAwarenessInternal@8 +GetProcessWindowStation@0 +GetProgmanWindow@0 +GetPropA@8 +GetPropW@8 +GetQueueStatus@4 +GetRawInputBuffer@12 +GetRawInputData@20 +GetRawInputDeviceInfoA@16 +GetRawInputDeviceInfoW@16 +GetRawInputDeviceList@12 +GetRawPointerDeviceData@20 +GetReasonTitleFromReasonCode@12 +GetRegisteredRawInputDevices@12 +GetQueueStatus@4 +GetScrollBarInfo@12 +GetScrollInfo@12 +GetScrollPos@8 +GetScrollRange@16 +GetSendMessageReceiver@4 +GetShellWindow@0 +GetSubMenu@8 +GetSysColor@4 +GetSysColorBrush@4 +GetSystemMenu@8 +GetSystemMetrics@4 +GetTabbedTextExtentA@20 +GetTabbedTextExtentW@20 +GetTaskmanWindow@0 +GetThreadDesktop@4 +GetTitleBarInfo@8 +GetTopLevelWindow@4 +GetTopWindow@4 +GetTouchInputInfo@16 +GetUnpredictedMessagePos@0 +GetUpdateRect@12 +GetUpdateRgn@12 +GetUpdatedClipboardFormats@12 +GetUserObjectInformationA@20 +GetUserObjectInformationW@20 +GetUserObjectSecurity@20 +GetWinStationInfo@4 +GetWindow@8 +GetWindowBand@8 +GetWindowCompositionAttribute@8 +GetWindowCompositionInfo@8 +GetWindowContextHelpId@4 +GetWindowDC@4 +GetWindowDisplayAffinity@8 +GetWindowFeedbackSetting@20 +GetWindowInfo@8 +GetWindowLongA@8 +GetWindowLongW@8 +GetWindowMinimizeRect@8 +GetWindowModuleFileName@12 +GetWindowModuleFileNameA@12 +GetWindowModuleFileNameW@12 +GetWindowPlacement@8 +GetWindowRect@8 +GetWindowRgn@8 +GetWindowRgnBox@8 +GetWindowRgnEx@12 +GetWindowTextA@12 +GetWindowTextLengthA@4 +GetWindowTextLengthW@4 +GetWindowTextW@12 +GetWindowThreadProcessId@8 +GetWindowWord@8 +GhostWindowFromHungWindow@4 +GrayStringA@36 +GrayStringW@36 +HideCaret@4 +HiliteMenuItem@16 +HungWindowFromGhostWindow@4 +IMPGetIMEA@8 +IMPGetIMEW@8 +IMPQueryIMEA@4 +IMPQueryIMEW@4 +IMPSetIMEA@8 +IMPSetIMEW@8 +ImpersonateDdeClientWindow@8 +InSendMessage@0 +InSendMessageEx@4 +InflateRect@12 +InitializeLpkHooks@4 +InitializeWin32EntryTable@4 +InitializeTouchInjection@8 +InjectTouchInput@8 +InsertMenuA@20 +InsertMenuItemA@16 +InsertMenuItemW@16 +InsertMenuW@20 +InternalGetWindowIcon@8 +;ord_2001@4 @2001 +;ord_2002@4 @2002 +InternalGetWindowText@12 +IntersectRect@12 +;ord_2005@4 @2005 +InvalidateRect@12 +InvalidateRgn@12 +InvertRect@8 +IsCharAlphaA@4 +;ord_2010@16 @2010 +IsCharAlphaNumericA@4 +IsCharAlphaNumericW@4 +IsCharAlphaW@4 +IsCharLowerA@4 +IsCharLowerW@4 +IsCharUpperA@4 +IsCharUpperW@4 +IsChild@8 +IsClipboardFormatAvailable@4 +IsDialogMessage@8 +IsDialogMessageA@8 +IsDialogMessageW@8 +IsDlgButtonChecked@8 +IsGUIThread@4 +IsHungAppWindow@4 +IsIconic@4 +IsImmersiveProcess@4 +IsInDesktopWindowBand@4 +IsMenu@4 +IsProcess16Bit@0 +IsMouseInPointerEnabled@0 +IsProcessDPIAware@0 +IsQueueAttached@0 +IsRectEmpty@4 +IsSETEnabled@0 +IsServerSideWindow@4 +IsThreadDesktopComposited@0 +IsTopLevelWindow@4 +IsTouchWindow@8 +IsWinEventHookInstalled@4 +IsWindow@4 +IsWindowEnabled@4 +IsWindowInDestroy@4 +IsWindowRedirectedForPrint@4 +IsWindowUnicode@4 +IsWindowVisible@4 +IsWow64Message@0 +IsZoomed@4 +KillSystemTimer@8 +KillTimer@8 +LoadAcceleratorsA@8 +LoadAcceleratorsW@8 +LoadBitmapA@8 +LoadBitmapW@8 +LoadCursorA@8 +LoadCursorFromFileA@4 +LoadCursorFromFileW@4 +;ord_2000@0 @2000 +;ord_2001@4 @2001 +;ord_2002@4 @2002 +LoadCursorW@8 +LoadIconA@8 +;ord_2005@4 @2005 +LoadIconW@8 +LoadImageA@24 +LoadImageW@24 +LoadKeyboardLayoutA@8 +LoadKeyboardLayoutEx@12 +LoadKeyboardLayoutW@8 +LoadLocalFonts@0 +LoadMenuA@8 +LoadMenuIndirectA@4 +LoadMenuIndirectW@4 +LoadMenuW@8 +LoadRemoteFonts@0 +LoadStringA@16 +LoadStringW@16 +LockSetForegroundWindow@4 +LockWindowStation@4 +LockWindowUpdate@4 +LockWorkStation@0 +LogicalToPhysicalPoint@8 +LogicalToPhysicalPointForPerMonitorDPI@8 +LookupIconIdFromDirectory@8 +LookupIconIdFromDirectoryEx@20 +MBToWCSEx@24 +MBToWCSExt@20 +MB_GetString@4 +MapDialogRect@8 +MapVirtualKeyA@8 +MapVirtualKeyExA@12 +MapVirtualKeyExW@12 +MapVirtualKeyW@8 +MapWindowPoints@16 +MenuItemFromPoint@16 +MenuWindowProcA@20 +MenuWindowProcW@20 +MessageBeep@4 +MessageBoxA@16 +MessageBoxExA@20 +MessageBoxExW@20 +MessageBoxIndirectA@4 +MessageBoxIndirectW@4 +MessageBoxTimeoutA@24 +MessageBoxTimeoutW@24 +MessageBoxW@16 +ModifyMenuA@20 +ModifyMenuW@20 +MonitorFromPoint@12 +MonitorFromRect@8 +MonitorFromWindow@8 +MoveWindow@24 +MsgWaitForMultipleObjects@20 +MsgWaitForMultipleObjectsEx@20 +NotifyOverlayWindow@8 +NotifyWinEvent@16 +OemKeyScan@4 +OemToCharA@8 +OemToCharBuffA@12 +OemToCharBuffW@12 +OemToCharW@8 +OffsetRect@12 +OpenClipboard@4 +OpenDesktopA@16 +OpenDesktopW@16 +OpenIcon@4 +OpenInputDesktop@12 +OpenThreadDesktop@16 +OpenWindowStationA@12 +OpenWindowStationW@12 +PackDDElParam@12 +PackTouchHitTestingProximityEvaluation@8 +PaintDesktop@4 +PaintMenuBar@24 +PaintMonitor@12 +PeekMessageA@20 +PeekMessageW@20 +PhysicalToLogicalPoint@8 +PhysicalToLogicalPointForPerMonitorDPI@8 +PostMessageA@16 +PostMessageW@16 +PostQuitMessage@4 +PostThreadMessageA@16 +PostThreadMessageW@16 +PrintWindow@12 +PrivateExtractIconExA@20 +PrivateExtractIconExW@20 +PrivateExtractIconsA@32 +PrivateExtractIconsW@32 +PrivateSetDbgTag@8 +PrivateSetRipFlags@8 +PrivateRegisterICSProc@4 +PtInRect@12 +QueryBSDRWindow@0 +QueryDisplayConfig@24 +QuerySendMessage@4 +QueryUserCounters@20 +RealChildWindowFromPoint@12 +RealGetWindowClass@12 +RealGetWindowClassA@12 +RealGetWindowClassW@12 +ReasonCodeNeedsBugID@4 +ReasonCodeNeedsComment@4 +RecordShutdownReason@4 +RedrawWindow@16 +RegisterBSDRWindow@8 +RegisterClassA@4 +RegisterClassExA@4 +RegisterClassExW@4 +RegisterClassW@4 +RegisterClipboardFormatA@4 +RegisterClipboardFormatW@4 +RegisterDeviceNotificationA@12 +RegisterDeviceNotificationW@12 +RegisterErrorReportingDialog@8 +RegisterFrostWindow@8 +RegisterGhostWindow@8 +RegisterHotKey@16 +RegisterPowerSettingNotification@12 +RegisterLogonProcess@8 +RegisterMessagePumpHook@4 +RegisterPointerDeviceNotifications@8 +RegisterPointerInputTarget@8 +RegisterPowerSettingNotification@12 +RegisterRawInputDevices@12 +RegisterServicesProcess@4 +RegisterSessionPort@4 ; Undocumented, rumored to be related to ALPC - http://blogs.msdn.com/b/ntdebugging/archive/2007/07/26/lpc-local-procedure-calls-part-1-architecture.aspx +RegisterShellHookWindow@4 +RegisterSuspendResumeNotification@8 +RegisterSystemThread@8 +RegisterTasklist@4 +RegisterTouchHitTestingWindow@8 +RegisterTouchWindow@8 +RegisterUserApiHook@4 ; Prototype changed in 2003 - https://www.reactos.org/wiki/Techwiki:RegisterUserApiHook +RegisterWindowMessageA@4 +RegisterWindowMessageW@4 +ReleaseCapture@0 +ReleaseDC@8 +RemoveClipboardFormatListener@4 +RemoveMenu@12 +RemovePropA@8 +RemovePropW@8 +ReplyMessage@4 +ResolveDesktopForWOW@4 +ReuseDDElParam@20 +ScreenToClient@8 +ScrollChildren@12 +ScrollDC@28 +ScrollWindow@20 +ScrollWindowEx@32 +SendDlgItemMessageA@20 +SendDlgItemMessageW@20 +SendIMEMessageExA@8 +SendIMEMessageExW@8 +SendInput@12 +SendMessageA@16 +SendMessageCallbackA@24 +SendMessageCallbackW@24 +SendMessageTimeoutA@28 +SendMessageTimeoutW@28 +SendMessageW@16 +SendNotifyMessageA@16 +SendNotifyMessageW@16 +SetActiveWindow@4 +SetCapture@4 +SetCaretBlinkTime@4 +SetCaretPos@8 +SetClassLongA@12 +SetClassLongW@12 +SetClassWord@12 +SetClipboardData@8 +SetClipboardViewer@4 +SetConsoleReserveKeys@8 +SetCoalescableTimer@20 +SetCursor@4 +SetCursorContents@8 +SetCursorPos@8 +SetDebugErrorLevel@4 +SetDeskWallpaper@4 +SetDisplayAutoRotationPreferences@4 +SetDisplayConfig@20 +SetDlgItemInt@16 +SetDlgItemTextA@12 +SetDlgItemTextW@12 +SetDoubleClickTime@4 +SetFocus@4 +SetForegroundWindow@4 +SetGestureConfig@20 +SetImmersiveBackgroundWindow@4 +SetInternalWindowPos@16 +SetKeyboardState@4 +SetLastErrorEx@8 +SetLayeredWindowAttributes@16 +SetLogonNotifyWindow@4 +SetMagnificationDesktopColorEffect@4 +SetMagnificationDesktopMagnification@16 +SetMagnificationLensCtxInformation@16 +SetMenu@8 +SetMenuContextHelpId@8 +SetMenuDefaultItem@12 +SetMenuInfo@8 +SetMenuItemBitmaps@20 +SetMenuItemInfoA@16 +SetMenuItemInfoW@16 +SetMessageExtraInfo@4 +SetMessageQueue@4 +SetMirrorRendering@8 +SetParent@8 +SetPhysicalCursorPos@8 +SetProcessDPIAware@0 +SetProcessDefaultLayout@4 +SetProcessDpiAwarenessInternal@4 +SetProcessRestrictionExemption@4 +SetProcessWindowStation@4 +SetProgmanWindow@4 +SetPropA@12 +SetPropW@12 +SetRect@20 +SetRectEmpty@4 +SetScrollInfo@16 +SetScrollPos@16 +SetScrollRange@20 +SetShellWindow@4 +SetShellWindowEx@8 +SetSysColors@12 +SetSysColorsTemp@12 +SetSystemCursor@8 +SetSystemMenu@8 +SetSystemTimer@16 +SetTaskmanWindow@4 +SetThreadDesktop@4 +SetThreadInputBlocked@8 +SetTimer@16 +SetUserObjectInformationA@16 +SetUserObjectInformationW@16 +SetUserObjectSecurity@12 +SetWinEventHook@28 +SetWindowBand@12 +SetWindowCompositionAttribute@8 +SetWindowCompositionTransition@28 +SetWindowContextHelpId@8 +SetWindowDisplayAffinity@8 +SetWindowFeedbackSetting@20 +SetWindowLongA@12 +SetWindowLongW@12 +SetWindowPlacement@8 +SetWindowPos@28 +SetWindowRgn@12 +SetWindowRgnEx@12 +SetWindowStationUser@16 +SetWindowTextA@8 +SetWindowTextW@8 +SetWindowWord@12 +SetWindowsHookA@8 +SetWindowsHookExA@16 +SetWindowsHookExW@16 +SetWindowsHookW@8 +SfmDxBindSwapChain@12 +SfmDxGetSwapChainStats@8 +SfmDxOpenSwapChain@16 +SfmDxQuerySwapChainBindingStatus@12 +SfmDxReleaseSwapChain@8 +SfmDxReportPendingBindingsToDwm@0 +SfmDxSetSwapChainBindingStatus@8 +SfmDxSetSwapChainStats@8 +ShowCaret@4 +ShowCursor@4 +ShowOwnedPopups@8 +ShowScrollBar@12 +ShowStartGlass@4 +ShowSystemCursor@4 +ShowWindow@8 +ShowWindowAsync@8 +ShutdownBlockReasonCreate@8 +ShutdownBlockReasonDestroy@4 +ShutdownBlockReasonQuery@12 +SignalRedirectionStartComplete@0 +SkipPointerFrameMessages@4 +SoftModalMessageBox@4 +SoundSentry@0 +SubtractRect@12 +SwapMouseButton@4 +SwitchDesktop@4 +SwitchDesktopWithFade@12 ; Same as SwithDesktop(), only with fade (done at log-in), only usable by winlogon - http://blog.airesoft.co.uk/2010/08/things-microsoft-can-do-that-you-cant/ +SwitchToThisWindow@8 +SystemParametersInfoA@16 +SystemParametersInfoW@16 +TabbedTextOutA@32 +TabbedTextOutW@32 +TileChildWindows@8 +TileWindows@20 +ToAscii@20 +ToAsciiEx@24 +ToUnicode@24 +ToUnicodeEx@28 +TrackMouseEvent@4 +TrackPopupMenu@28 +TrackPopupMenuEx@24 +TranslateAccelerator@12 +TranslateAcceleratorA@12 +TranslateAcceleratorW@12 +TranslateMDISysAccel@8 +TranslateMessage@4 +TranslateMessageEx@8 +UnhookWinEvent@4 +UnhookWindowsHook@8 +UnhookWindowsHookEx@4 +UnionRect@12 +UnloadKeyboardLayout@4 +UnlockWindowStation@4 +UnpackDDElParam@16 +UnregisterClassA@8 +UnregisterClassW@8 +UnregisterDeviceNotification@4 +UnregisterHotKey@8 +UnregisterMessagePumpHook@0 +UnregisterPointerInputTarget@8 +UnregisterPowerSettingNotification@4 +UnregisterSessionPort@0 +UnregisterSuspendResumeNotification@4 +UnregisterTouchWindow@4 +UnregisterUserApiHook@0 +UpdateDefaultDesktopThumbnail@20 +UpdateLayeredWindow@36 +UpdateLayeredWindowIndirect@8 +UpdatePerUserSystemParameters@4 ; Undocumented, seems to apply certain registry settings to desktop, etc. ReactOS has @8 version - http://doxygen.reactos.org/d0/d92/win32ss_2user_2user32_2misc_2misc_8c_a1ff565f0af6bac6dce604f9f4473fe79.html ; @4 is rumored to be without the first DWORD +UpdateWindow@4 +UpdateWindowInputSinkHints@8 +UpdateWindowTransform@12 +User32InitializeImmEntryTable@4 +UserClientDllInitialize@12 +UserHandleGrantAccess@12 +UserLpkPSMTextOut@24 +UserLpkTabbedTextOut@48 +UserRealizePalette@4 +UserRegisterWowHandlers@8 +VRipOutput@0 +VTagOutput@0 +ValidateRect@8 +ValidateRgn@8 +VkKeyScanA@4 +VkKeyScanExA@8 +VkKeyScanExW@8 +VkKeyScanW@4 +WCSToMBEx@24 +WINNLSEnableIME@8 +WINNLSGetEnableStatus@4 +WINNLSGetIMEHotkey@4 +WaitForInputIdle@8 +WaitForRedirectionStartComplete@0 +WaitMessage@0 +Win32PoolAllocationStats@24 +WinHelpA@16 +WinHelpW@16 +WindowFromDC@4 +WindowFromPhysicalPoint@8 +WindowFromPoint@8 +_UserTestTokenForInteractive@8 +gSharedInfo DATA +gapfnScSendMessage DATA +keybd_event@16 +mouse_event@20 +wsprintfA +wsprintfW +wvsprintfA@12 +wvsprintfW@12 +;ord_2500@16 @2500 +;ord_2501@12 @2501 +;ord_2502@8 @2502 +;ord_2503@24 @2503 +;ord_2504@8 @2504 +;ord_2505@8 @2505 +;ord_2506@12 @2506 +;ord_2507@4 @2507 +;ord_2508@8 @2508 +;ord_2509@4 @2509 +;ord_2510@12 @2510 +;ord_2511@8 @2511 +;ord_2512@12 @2512 +;ord_2513@4 @2513 +;ord_2514@8 @2514 +;ord_2515@8 @2515 +;ord_2516@12 @2516 +;ord_2517@4 @2517 +;ord_2518@0 @2518 +;ord_2519@4 @2519 +;ord_2520@0 @2520 +;ord_2521@8 @2521 +;ord_2522@4 @2522 +;ord_2523@8 @2523 +;ord_2524@8 @2524 +;ord_2525@12 @2525 +;ord_2526@12 @2526 +;ord_2527@12 @2527 +IsThreadMessageQueueAttached@4 +;ord_2529@4 @2529 +;ord_2530@8 @2530 +;ord_2531@16 @2531 +;ord_2532@8 @2532 +;ord_2533@4 @2533 +;ord_2534@8 @2534 +;ord_2535@0 @2535 +;ord_2536@8 @2536 +;ord_2537@16 @2537 +;ord_2538@4 @2538 +;ord_2539@4 @2539 +;ord_2540@4 @2540 +;ord_2541@0 @2541 +;ord_2544@4 @2544 +;ord_2545@8 @2545 +;ord_2546@4 @2546 +;ord_2547@4 @2547 +;ord_2548@4 @2548 +;ord_2549@4 @2549 +;ord_2550@8 @2550 +;ord_2551@20 @2551 +;ord_2552@8 @2552 +;ord_2553@32 @2553 +;ord_2554@12 @2554 +;ord_2555@16 @2555 +;ord_2556@8 @2556 +;ord_2557@12 @2557 +;ord_2558@12 @2558 +;ord_2559@16 @2559 +;ord_2560@20 @2560 +;ord_2561@0 @2561 +;ord_2562@0 @2562 +;ord_2563@0 @2563 From 212171643c0cd0c9065f0e7322b4d373f51a089b Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Thu, 1 Oct 2020 11:38:19 +0200 Subject: [PATCH 15/55] stage2: Add missing defines for building dllcrt2.o Closes #6482 --- src/mingw.zig | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/mingw.zig b/src/mingw.zig index b6c8591ea4..ff4156cfb9 100644 --- a/src/mingw.zig +++ b/src/mingw.zig @@ -32,6 +32,8 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void { var args = std.ArrayList([]const u8).init(arena); try add_cc_args(comp, arena, &args); try args.appendSlice(&[_][]const u8{ + "-D_SYSCRT=1", + "-DCRTDLL=1", "-U__CRTDLL__", "-D__MSVCRT__", // Uncomment these 3 things for crtu @@ -53,6 +55,8 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void { var args = std.ArrayList([]const u8).init(arena); try add_cc_args(comp, arena, &args); try args.appendSlice(&[_][]const u8{ + "-D_SYSCRT=1", + "-DCRTDLL=1", "-U__CRTDLL__", "-D__MSVCRT__", }); @@ -437,11 +441,8 @@ fn findDef(comp: *Compilation, allocator: *Allocator, lib_name: []const u8) ![]u const lib_path = switch (target.cpu.arch) { .i386 => "lib32", .x86_64 => "lib64", - .arm, .armeb => switch (target.cpu.arch.ptrBitWidth()) { - 32 => "libarm32", - 64 => "libarm64", - else => unreachable, - }, + .arm, .armeb, .thumb, .thumbeb, .aarch64_32 => "libarm32", + .aarch64, .aarch64_be => "libarm64", else => unreachable, }; From bf0afaa876391571f6072650bf450356b26c928d Mon Sep 17 00:00:00 2001 From: Alexandros Naskos Date: Thu, 1 Oct 2020 16:50:05 +0300 Subject: [PATCH 16/55] std.event.Loop.runDetached should be pub --- lib/std/event/loop.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/event/loop.zig b/lib/std/event/loop.zig index cb0aa63dbe..cf220bf775 100644 --- a/lib/std/event/loop.zig +++ b/lib/std/event/loop.zig @@ -649,7 +649,7 @@ pub const Loop = struct { /// Runs the provided function asynchonously, similarly to Go's "go" operator. /// `func` must return void and it can be an async function. - fn runDetached(self: *Loop, alloc: *mem.Allocator, comptime func: anytype, args: anytype) error{OutOfMemory}!void { + pub fn runDetached(self: *Loop, alloc: *mem.Allocator, comptime func: anytype, args: anytype) error{OutOfMemory}!void { if (!std.io.is_async) @compileError("Can't use runDetached in non-async mode!"); if (@TypeOf(@call(.{}, func, args)) != void) { @compileError("`func` must not have a return value"); From 8acfcf4e0d2edc4b66a0fe80d5fbb9c8898248bb Mon Sep 17 00:00:00 2001 From: markfirmware Date: Thu, 1 Oct 2020 13:15:35 -0400 Subject: [PATCH 17/55] Update build.zig Fixes #6477 --- lib/std/build.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index 7e3c75bc78..a3b4d78c04 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -2168,7 +2168,7 @@ pub const LibExeObjStep = struct { } if (self.linker_script) |linker_script| { - zig_args.append("--linker-script") catch unreachable; + try zig_args.append("--script"); zig_args.append(builder.pathFromRoot(linker_script)) catch unreachable; } From 1296e4a8572864d9a3618e5ac28d0cdfd5c08730 Mon Sep 17 00:00:00 2001 From: markfirmware Date: Thu, 1 Oct 2020 15:27:08 -0400 Subject: [PATCH 18/55] Update build.zig --- lib/std/build.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index a3b4d78c04..292aeb63cd 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -2169,7 +2169,7 @@ pub const LibExeObjStep = struct { if (self.linker_script) |linker_script| { try zig_args.append("--script"); - zig_args.append(builder.pathFromRoot(linker_script)) catch unreachable; + try zig_args.append(builder.pathFromRoot(linker_script)); } if (self.version_script) |version_script| { From 5c84f9dad456c54dcb1937d13837fabefa507135 Mon Sep 17 00:00:00 2001 From: Nathan Bourgeois Date: Thu, 1 Oct 2020 15:57:19 -0400 Subject: [PATCH 19/55] Patch in emit relocs support --- lib/std/build.zig | 4 ++++ src/Compilation.zig | 3 +++ src/link.zig | 1 + src/link/Elf.zig | 5 +++++ src/main.zig | 5 +++++ 5 files changed, 18 insertions(+) diff --git a/lib/std/build.zig b/lib/std/build.zig index 7e3c75bc78..88d416bee6 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -1239,6 +1239,7 @@ pub const LibExeObjStep = struct { /// Create a .eh_frame_hdr section and a PT_GNU_EH_FRAME segment in the ELF /// file. link_eh_frame_hdr: bool = false, + link_emit_relocs: bool = false, /// Place every function in its own section so that unused ones may be /// safely garbage-collected during the linking phase. @@ -2075,6 +2076,9 @@ pub const LibExeObjStep = struct { if (self.link_eh_frame_hdr) { try zig_args.append("--eh-frame-hdr"); } + if(self.link_emit_relocs){ + try zig_args.append("-emit-relocs"); + } if (self.link_function_sections) { try zig_args.append("-ffunction-sections"); } diff --git a/src/Compilation.zig b/src/Compilation.zig index 623635a6b0..fc801c7789 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -352,6 +352,7 @@ pub const InitOptions = struct { time_report: bool = false, stack_report: bool = false, link_eh_frame_hdr: bool = false, + link_emit_relocs: bool = false, linker_script: ?[]const u8 = null, version_script: ?[]const u8 = null, override_soname: ?[]const u8 = null, @@ -447,6 +448,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { options.system_libs.len != 0 or options.link_libc or options.link_libcpp or options.link_eh_frame_hdr or + options.link_emit_relocs or options.output_mode == .Lib or options.lld_argv.len != 0 or options.linker_script != null or options.version_script != null) @@ -769,6 +771,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { .version_script = options.version_script, .gc_sections = options.linker_gc_sections, .eh_frame_hdr = options.link_eh_frame_hdr, + .emit_relocs = options.link_emit_relocs, .rdynamic = options.rdynamic, .extra_lld_args = options.lld_argv, .override_soname = options.override_soname, diff --git a/src/link.zig b/src/link.zig index 4d28c8a1a7..3b00684170 100644 --- a/src/link.zig +++ b/src/link.zig @@ -60,6 +60,7 @@ pub const Options = struct { link_libcpp: bool, function_sections: bool, eh_frame_hdr: bool, + emit_relocs: bool, rdynamic: bool, z_nodelete: bool, z_defs: bool, diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 38b9b1acca..0030b2b738 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1286,6 +1286,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { man.hash.add(stack_size); man.hash.add(gc_sections); man.hash.add(self.base.options.eh_frame_hdr); + man.hash.add(self.base.options.emit_relocs) man.hash.add(self.base.options.rdynamic); man.hash.addListOfBytes(self.base.options.extra_lld_args); man.hash.addListOfBytes(self.base.options.lib_dirs); @@ -1364,6 +1365,10 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { if (self.base.options.eh_frame_hdr) { try argv.append("--eh-frame-hdr"); } + + if (self.base.options.emit_relocs) { + try argv.append("-emit-relocs"); + } if (self.base.options.rdynamic) { try argv.append("--export-dynamic"); diff --git a/src/main.zig b/src/main.zig index d421322c17..d365698d11 100644 --- a/src/main.zig +++ b/src/main.zig @@ -273,6 +273,7 @@ const usage_build_generic = \\ -rdynamic Add all symbols to the dynamic symbol table \\ -rpath [path] Add directory to the runtime library search path \\ --eh-frame-hdr Enable C++ exception handling by passing --eh-frame-hdr to linker + \\ -emit-relocs Enable output of relocation sections for post build tools \\ -dynamic Force output to be dynamically linked \\ -static Force output to be statically linked \\ -Bsymbolic Bind global references locally @@ -438,6 +439,7 @@ fn buildOutputType( var use_lld: ?bool = null; var use_clang: ?bool = null; var link_eh_frame_hdr = false; + var link_emit_relocs = false; var each_lib_rpath = false; var libc_paths_file: ?[]const u8 = null; var machine_code_model: std.builtin.CodeModel = .default; @@ -838,6 +840,8 @@ fn buildOutputType( function_sections = true; } else if (mem.eql(u8, arg, "--eh-frame-hdr")) { link_eh_frame_hdr = true; + } else if (mem.eql(u8, arg, "-emit-relocs")) { + link_emit_relocs = true; } else if (mem.eql(u8, arg, "-Bsymbolic")) { linker_bind_global_refs_locally = true; } else if (mem.eql(u8, arg, "--verbose-link")) { @@ -1580,6 +1584,7 @@ fn buildOutputType( .linker_z_nodelete = linker_z_nodelete, .linker_z_defs = linker_z_defs, .link_eh_frame_hdr = link_eh_frame_hdr, + .link_emit_relocs = link_emit_relocs, .stack_size_override = stack_size_override, .strip = strip, .single_threaded = single_threaded, From 77df5dae7f69f0d46c8e229df12f43f33487073f Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Sat, 26 Sep 2020 08:31:08 -0600 Subject: [PATCH 20/55] Make builtin.TypeInfo.Pointer.alignment u29 instead of comptime_int --- lib/std/builtin.zig | 2 +- src/stage1/ir.cpp | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 52b8f641cd..cca47fbc01 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -214,7 +214,7 @@ pub const TypeInfo = union(enum) { size: Size, is_const: bool, is_volatile: bool, - alignment: comptime_int, + alignment: u29, child: type, is_allowzero: bool, diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp index 7de4b923ba..51b9900b6e 100644 --- a/src/stage1/ir.cpp +++ b/src/stage1/ir.cpp @@ -25029,7 +25029,7 @@ static ZigValue *create_ptr_like_type_info(IrAnalyze *ira, IrInst *source_instr, fields[2]->data.x_bool = attrs_type->data.pointer.is_volatile; // alignment: u32 ensure_field_index(result->type, "alignment", 3); - fields[3]->type = ira->codegen->builtin_types.entry_num_lit_int; + fields[3]->type = ira->codegen->builtin_types.entry_u29; if (attrs_type->data.pointer.explicit_alignment != 0) { fields[3]->special = ConstValSpecialStatic; bigint_init_unsigned(&fields[3]->data.x_bigint, attrs_type->data.pointer.explicit_alignment); @@ -25740,6 +25740,17 @@ static Error get_const_field_bool(IrAnalyze *ira, AstNode *source_node, ZigValue return ErrorNone; } +static Error get_const_field_u29(IrAnalyze *ira, AstNode *source_node, ZigValue *struct_value, + const char *name, size_t field_index, uint32_t *out) +{ + ZigValue *value = get_const_field(ira, source_node, struct_value, name, field_index); + if (value == nullptr) + return ErrorSemanticAnalyzeFail; + assert(value->type == ira->codegen->builtin_types.entry_u29); + *out = bigint_as_u32(&value->data.x_bigint); + return ErrorNone; +} + static BigInt *get_const_field_lit_int(IrAnalyze *ira, AstNode *source_node, ZigValue *struct_value, const char *name, size_t field_index) { ZigValue *value = get_const_field(ira, source_node, struct_value, name, field_index); @@ -25868,8 +25879,9 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI buf_sprintf("sentinels are only allowed on slices and unknown-length pointers")); return ira->codegen->invalid_inst_gen->value->type; } - BigInt *bi = get_const_field_lit_int(ira, source_instr->source_node, payload, "alignment", 3); - if (bi == nullptr) + + uint32_t alignment; + if ((err = get_const_field_u29(ira, source_instr->source_node, payload, "alignment", 3, &alignment))) return ira->codegen->invalid_inst_gen->value->type; bool is_const; @@ -25896,7 +25908,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI is_const, is_volatile, ptr_len, - bigint_as_u32(bi), + alignment, 0, // bit_offset_in_host 0, // host_int_bytes is_allowzero, From d81648ce8ce93780c7eb8c93f05b6f99f160474c Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Sat, 26 Sep 2020 08:48:26 -0600 Subject: [PATCH 21/55] Add alignment field to TypeInfo.UnionField and TypeInfo.StructField Closes https://github.com/ziglang/zig/issues/6122 --- lib/std/builtin.zig | 2 ++ lib/std/meta/trailer_flags.zig | 1 + src/stage1/ir.cpp | 16 ++++++++++++++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index cca47fbc01..857ecc391f 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -262,6 +262,7 @@ pub const TypeInfo = union(enum) { field_type: type, default_value: anytype, is_comptime: bool, + alignment: u29, }; /// This data structure is used by the Zig language code generation and @@ -318,6 +319,7 @@ pub const TypeInfo = union(enum) { pub const UnionField = struct { name: []const u8, field_type: type, + alignment: u29, }; /// This data structure is used by the Zig language code generation and diff --git a/lib/std/meta/trailer_flags.zig b/lib/std/meta/trailer_flags.zig index c8c1323686..6cd8dc9357 100644 --- a/lib/std/meta/trailer_flags.zig +++ b/lib/std/meta/trailer_flags.zig @@ -47,6 +47,7 @@ pub fn TrailerFlags(comptime Fields: type) type { @as(?struct_field.field_type, null), ), .is_comptime = false, + .alignment = @alignOf(?struct_field.field_type), }; } break :blk @Type(.{ diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp index 51b9900b6e..5c58b0cb5a 100644 --- a/src/stage1/ir.cpp +++ b/src/stage1/ir.cpp @@ -25431,11 +25431,15 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy union_field_val->special = ConstValSpecialStatic; union_field_val->type = type_info_union_field_type; - ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 2); + ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 3); inner_fields[1]->special = ConstValSpecialStatic; inner_fields[1]->type = ira->codegen->builtin_types.entry_type; inner_fields[1]->data.x_type = union_field->type_entry; + inner_fields[2]->special = ConstValSpecialStatic; + inner_fields[2]->type = ira->codegen->builtin_types.entry_u29; + bigint_init_unsigned(&inner_fields[2]->data.x_bigint, union_field->align); + ZigValue *name = create_const_str_lit(ira->codegen, union_field->name)->data.x_ptr.data.ref.pointee; init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(union_field->name), true); @@ -25502,7 +25506,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy struct_field_val->special = ConstValSpecialStatic; struct_field_val->type = type_info_struct_field_type; - ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 4); + ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 5); inner_fields[1]->special = ConstValSpecialStatic; inner_fields[1]->type = ira->codegen->builtin_types.entry_type; @@ -25522,6 +25526,10 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy inner_fields[3]->type = ira->codegen->builtin_types.entry_bool; inner_fields[3]->data.x_bool = struct_field->is_comptime; + inner_fields[4]->special = ConstValSpecialStatic; + inner_fields[4]->type = ira->codegen->builtin_types.entry_u29; + bigint_init_unsigned(&inner_fields[4]->data.x_bigint, struct_field->align); + ZigValue *name = create_const_str_lit(ira->codegen, struct_field->name)->data.x_ptr.data.ref.pointee; init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(struct_field->name), true); @@ -26145,6 +26153,8 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI } if ((err = get_const_field_bool(ira, source_instr->source_node, field_value, "is_comptime", 3, &field->is_comptime))) return ira->codegen->invalid_inst_gen->value->type; + if ((err = get_const_field_u29(ira, source_instr->source_node, field_value, "alignment", 4, &field->align))) + return ira->codegen->invalid_inst_gen->value->type; } return entry; @@ -26314,6 +26324,8 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI return ira->codegen->invalid_inst_gen->value->type; field->type_val = type_value; field->type_entry = type_value->data.x_type; + if ((err = get_const_field_u29(ira, source_instr->source_node, field_value, "alignment", 2, &field->align))) + return ira->codegen->invalid_inst_gen->value->type; } return entry; } From c2ee66108c399b0359ce996980bd8593c3eb22ef Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Sat, 26 Sep 2020 08:55:32 -0600 Subject: [PATCH 22/55] Add tests for alignment field in UnionField and StructFIeld --- test/stage1/behavior/type_info.zig | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig index 9e066d5f1a..f5b37fe3f0 100644 --- a/test/stage1/behavior/type_info.zig +++ b/test/stage1/behavior/type_info.zig @@ -211,7 +211,9 @@ fn testUnion() void { expect(notag_union_info.Union.tag_type == null); expect(notag_union_info.Union.layout == .Auto); expect(notag_union_info.Union.fields.len == 2); + expect(notag_union_info.Union.fields[0].alignment == @alignOf(void)); expect(notag_union_info.Union.fields[1].field_type == u32); + expect(notag_union_info.Union.fields[1].alignment == @alignOf(u32)); const TestExternUnion = extern union { foo: *c_void, @@ -229,13 +231,18 @@ test "type info: struct info" { } fn testStruct() void { + const unpacked_struct_info = @typeInfo(TestUnpackedStruct); + expect(unpacked_struct_info.Struct.fields[0].alignment == @alignOf(u32)); + const struct_info = @typeInfo(TestStruct); expect(struct_info == .Struct); expect(struct_info.Struct.layout == .Packed); expect(struct_info.Struct.fields.len == 4); + expect(struct_info.Struct.fields[0].alignment == 2 * @alignOf(usize)); expect(struct_info.Struct.fields[2].field_type == *TestStruct); expect(struct_info.Struct.fields[2].default_value == null); expect(struct_info.Struct.fields[3].default_value.? == 4); + expect(struct_info.Struct.fields[3].alignment == 1); expect(struct_info.Struct.decls.len == 2); expect(struct_info.Struct.decls[0].is_pub); expect(!struct_info.Struct.decls[0].data.Fn.is_extern); @@ -244,8 +251,12 @@ fn testStruct() void { expect(struct_info.Struct.decls[0].data.Fn.fn_type == fn (*const TestStruct) void); } +const TestUnpackedStruct = struct { + fieldA: u32 = 4, +}; + const TestStruct = packed struct { - fieldA: usize, + fieldA: usize align(2 * @alignOf(usize)), fieldB: void, fieldC: *Self, fieldD: u32 = 4, From 70c507911a738538b8ef4df2b52184512e7d86a8 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Sat, 26 Sep 2020 09:55:38 -0600 Subject: [PATCH 23/55] Update @Type tests for alignment field in UnionField and StructFIeld --- test/stage1/behavior/type.zig | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/stage1/behavior/type.zig b/test/stage1/behavior/type.zig index 38d23175d0..1bb0823e74 100644 --- a/test/stage1/behavior/type.zig +++ b/test/stage1/behavior/type.zig @@ -320,8 +320,8 @@ test "Type.Union" { .layout = .Auto, .tag_type = null, .fields = &[_]TypeInfo.UnionField{ - .{ .name = "int", .field_type = i32 }, - .{ .name = "float", .field_type = f32 }, + .{ .name = "int", .field_type = i32, .alignment = @alignOf(f32) }, + .{ .name = "float", .field_type = f32, .alignment = @alignOf(f32) }, }, .decls = &[_]TypeInfo.Declaration{}, }, @@ -336,8 +336,8 @@ test "Type.Union" { .layout = .Packed, .tag_type = null, .fields = &[_]TypeInfo.UnionField{ - .{ .name = "signed", .field_type = i32 }, - .{ .name = "unsigned", .field_type = u32 }, + .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) }, + .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) }, }, .decls = &[_]TypeInfo.Declaration{}, }, @@ -363,8 +363,8 @@ test "Type.Union" { .layout = .Auto, .tag_type = Tag, .fields = &[_]TypeInfo.UnionField{ - .{ .name = "signed", .field_type = i32 }, - .{ .name = "unsigned", .field_type = u32 }, + .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) }, + .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) }, }, .decls = &[_]TypeInfo.Declaration{}, }, @@ -392,7 +392,7 @@ test "Type.Union from Type.Enum" { .layout = .Auto, .tag_type = Tag, .fields = &[_]TypeInfo.UnionField{ - .{ .name = "working_as_expected", .field_type = u32 }, + .{ .name = "working_as_expected", .field_type = u32, .alignment = @alignOf(u32) }, }, .decls = &[_]TypeInfo.Declaration{}, }, @@ -408,7 +408,7 @@ test "Type.Union from regular enum" { .layout = .Auto, .tag_type = E, .fields = &[_]TypeInfo.UnionField{ - .{ .name = "working_as_expected", .field_type = u32 }, + .{ .name = "working_as_expected", .field_type = u32, .alignment = @alignOf(u32) }, }, .decls = &[_]TypeInfo.Declaration{}, }, From a12203d2be2ff1021d8faa9b87c53af091f0bd01 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Sat, 26 Sep 2020 14:42:43 -0600 Subject: [PATCH 24/55] Switch TypeInfo alignment fields from u29 to comptime_int --- lib/std/builtin.zig | 6 +++--- src/stage1/ir.cpp | 37 +++++++++++++++++-------------------- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 857ecc391f..d80d0e88fe 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -214,7 +214,7 @@ pub const TypeInfo = union(enum) { size: Size, is_const: bool, is_volatile: bool, - alignment: u29, + alignment: comptime_int, child: type, is_allowzero: bool, @@ -262,7 +262,7 @@ pub const TypeInfo = union(enum) { field_type: type, default_value: anytype, is_comptime: bool, - alignment: u29, + alignment: comptime_int, }; /// This data structure is used by the Zig language code generation and @@ -319,7 +319,7 @@ pub const TypeInfo = union(enum) { pub const UnionField = struct { name: []const u8, field_type: type, - alignment: u29, + alignment: comptime_int, }; /// This data structure is used by the Zig language code generation and diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp index 5c58b0cb5a..8da207cab7 100644 --- a/src/stage1/ir.cpp +++ b/src/stage1/ir.cpp @@ -25027,9 +25027,9 @@ static ZigValue *create_ptr_like_type_info(IrAnalyze *ira, IrInst *source_instr, fields[2]->special = ConstValSpecialStatic; fields[2]->type = ira->codegen->builtin_types.entry_bool; fields[2]->data.x_bool = attrs_type->data.pointer.is_volatile; - // alignment: u32 + // alignment: comptime_int ensure_field_index(result->type, "alignment", 3); - fields[3]->type = ira->codegen->builtin_types.entry_u29; + fields[3]->type = ira->codegen->builtin_types.entry_num_lit_int; if (attrs_type->data.pointer.explicit_alignment != 0) { fields[3]->special = ConstValSpecialStatic; bigint_init_unsigned(&fields[3]->data.x_bigint, attrs_type->data.pointer.explicit_alignment); @@ -25432,12 +25432,14 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy union_field_val->type = type_info_union_field_type; ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 3); + // field_type: type inner_fields[1]->special = ConstValSpecialStatic; inner_fields[1]->type = ira->codegen->builtin_types.entry_type; inner_fields[1]->data.x_type = union_field->type_entry; + // alignment: comptime_int inner_fields[2]->special = ConstValSpecialStatic; - inner_fields[2]->type = ira->codegen->builtin_types.entry_u29; + inner_fields[2]->type = ira->codegen->builtin_types.entry_num_lit_int; bigint_init_unsigned(&inner_fields[2]->data.x_bigint, union_field->align); ZigValue *name = create_const_str_lit(ira->codegen, union_field->name)->data.x_ptr.data.ref.pointee; @@ -25522,12 +25524,14 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy } set_optional_payload(inner_fields[2], struct_field->init_val); + // is_comptime: bool inner_fields[3]->special = ConstValSpecialStatic; inner_fields[3]->type = ira->codegen->builtin_types.entry_bool; inner_fields[3]->data.x_bool = struct_field->is_comptime; + // alignment: comptime_int inner_fields[4]->special = ConstValSpecialStatic; - inner_fields[4]->type = ira->codegen->builtin_types.entry_u29; + inner_fields[4]->type = ira->codegen->builtin_types.entry_num_lit_int; bigint_init_unsigned(&inner_fields[4]->data.x_bigint, struct_field->align); ZigValue *name = create_const_str_lit(ira->codegen, struct_field->name)->data.x_ptr.data.ref.pointee; @@ -25748,17 +25752,6 @@ static Error get_const_field_bool(IrAnalyze *ira, AstNode *source_node, ZigValue return ErrorNone; } -static Error get_const_field_u29(IrAnalyze *ira, AstNode *source_node, ZigValue *struct_value, - const char *name, size_t field_index, uint32_t *out) -{ - ZigValue *value = get_const_field(ira, source_node, struct_value, name, field_index); - if (value == nullptr) - return ErrorSemanticAnalyzeFail; - assert(value->type == ira->codegen->builtin_types.entry_u29); - *out = bigint_as_u32(&value->data.x_bigint); - return ErrorNone; -} - static BigInt *get_const_field_lit_int(IrAnalyze *ira, AstNode *source_node, ZigValue *struct_value, const char *name, size_t field_index) { ZigValue *value = get_const_field(ira, source_node, struct_value, name, field_index); @@ -25888,8 +25881,8 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI return ira->codegen->invalid_inst_gen->value->type; } - uint32_t alignment; - if ((err = get_const_field_u29(ira, source_instr->source_node, payload, "alignment", 3, &alignment))) + BigInt *alignment = get_const_field_lit_int(ira, source_instr->source_node, payload, "alignment", 3); + if (alignment == nullptr) return ira->codegen->invalid_inst_gen->value->type; bool is_const; @@ -25916,7 +25909,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI is_const, is_volatile, ptr_len, - alignment, + bigint_as_u32(alignment), 0, // bit_offset_in_host 0, // host_int_bytes is_allowzero, @@ -26153,8 +26146,10 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI } if ((err = get_const_field_bool(ira, source_instr->source_node, field_value, "is_comptime", 3, &field->is_comptime))) return ira->codegen->invalid_inst_gen->value->type; - if ((err = get_const_field_u29(ira, source_instr->source_node, field_value, "alignment", 4, &field->align))) + BigInt *alignment = get_const_field_lit_int(ira, source_instr->source_node, field_value, "alignment", 4); + if (alignment == nullptr) return ira->codegen->invalid_inst_gen->value->type; + field->align = bigint_as_u32(alignment); } return entry; @@ -26324,8 +26319,10 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI return ira->codegen->invalid_inst_gen->value->type; field->type_val = type_value; field->type_entry = type_value->data.x_type; - if ((err = get_const_field_u29(ira, source_instr->source_node, field_value, "alignment", 2, &field->align))) + BigInt *alignment = get_const_field_lit_int(ira, source_instr->source_node, field_value, "alignment", 2); + if (alignment == nullptr) return ira->codegen->invalid_inst_gen->value->type; + field->align = bigint_as_u32(alignment); } return entry; } From 4566b273733be9508b6178742293008d8d66451e Mon Sep 17 00:00:00 2001 From: Nathan Bourgeois Date: Thu, 1 Oct 2020 15:57:19 -0400 Subject: [PATCH 25/55] Patch in emit relocs support --- lib/std/build.zig | 4 ++++ src/Compilation.zig | 3 +++ src/link.zig | 1 + src/link/Elf.zig | 5 +++++ src/main.zig | 5 +++++ 5 files changed, 18 insertions(+) diff --git a/lib/std/build.zig b/lib/std/build.zig index 7e3c75bc78..88d416bee6 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -1239,6 +1239,7 @@ pub const LibExeObjStep = struct { /// Create a .eh_frame_hdr section and a PT_GNU_EH_FRAME segment in the ELF /// file. link_eh_frame_hdr: bool = false, + link_emit_relocs: bool = false, /// Place every function in its own section so that unused ones may be /// safely garbage-collected during the linking phase. @@ -2075,6 +2076,9 @@ pub const LibExeObjStep = struct { if (self.link_eh_frame_hdr) { try zig_args.append("--eh-frame-hdr"); } + if(self.link_emit_relocs){ + try zig_args.append("-emit-relocs"); + } if (self.link_function_sections) { try zig_args.append("-ffunction-sections"); } diff --git a/src/Compilation.zig b/src/Compilation.zig index 623635a6b0..fc801c7789 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -352,6 +352,7 @@ pub const InitOptions = struct { time_report: bool = false, stack_report: bool = false, link_eh_frame_hdr: bool = false, + link_emit_relocs: bool = false, linker_script: ?[]const u8 = null, version_script: ?[]const u8 = null, override_soname: ?[]const u8 = null, @@ -447,6 +448,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { options.system_libs.len != 0 or options.link_libc or options.link_libcpp or options.link_eh_frame_hdr or + options.link_emit_relocs or options.output_mode == .Lib or options.lld_argv.len != 0 or options.linker_script != null or options.version_script != null) @@ -769,6 +771,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { .version_script = options.version_script, .gc_sections = options.linker_gc_sections, .eh_frame_hdr = options.link_eh_frame_hdr, + .emit_relocs = options.link_emit_relocs, .rdynamic = options.rdynamic, .extra_lld_args = options.lld_argv, .override_soname = options.override_soname, diff --git a/src/link.zig b/src/link.zig index 4d28c8a1a7..3b00684170 100644 --- a/src/link.zig +++ b/src/link.zig @@ -60,6 +60,7 @@ pub const Options = struct { link_libcpp: bool, function_sections: bool, eh_frame_hdr: bool, + emit_relocs: bool, rdynamic: bool, z_nodelete: bool, z_defs: bool, diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 38b9b1acca..aab7758505 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1286,6 +1286,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { man.hash.add(stack_size); man.hash.add(gc_sections); man.hash.add(self.base.options.eh_frame_hdr); + man.hash.add(self.base.options.emit_relocs); man.hash.add(self.base.options.rdynamic); man.hash.addListOfBytes(self.base.options.extra_lld_args); man.hash.addListOfBytes(self.base.options.lib_dirs); @@ -1364,6 +1365,10 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { if (self.base.options.eh_frame_hdr) { try argv.append("--eh-frame-hdr"); } + + if (self.base.options.emit_relocs) { + try argv.append("-emit-relocs"); + } if (self.base.options.rdynamic) { try argv.append("--export-dynamic"); diff --git a/src/main.zig b/src/main.zig index d421322c17..d365698d11 100644 --- a/src/main.zig +++ b/src/main.zig @@ -273,6 +273,7 @@ const usage_build_generic = \\ -rdynamic Add all symbols to the dynamic symbol table \\ -rpath [path] Add directory to the runtime library search path \\ --eh-frame-hdr Enable C++ exception handling by passing --eh-frame-hdr to linker + \\ -emit-relocs Enable output of relocation sections for post build tools \\ -dynamic Force output to be dynamically linked \\ -static Force output to be statically linked \\ -Bsymbolic Bind global references locally @@ -438,6 +439,7 @@ fn buildOutputType( var use_lld: ?bool = null; var use_clang: ?bool = null; var link_eh_frame_hdr = false; + var link_emit_relocs = false; var each_lib_rpath = false; var libc_paths_file: ?[]const u8 = null; var machine_code_model: std.builtin.CodeModel = .default; @@ -838,6 +840,8 @@ fn buildOutputType( function_sections = true; } else if (mem.eql(u8, arg, "--eh-frame-hdr")) { link_eh_frame_hdr = true; + } else if (mem.eql(u8, arg, "-emit-relocs")) { + link_emit_relocs = true; } else if (mem.eql(u8, arg, "-Bsymbolic")) { linker_bind_global_refs_locally = true; } else if (mem.eql(u8, arg, "--verbose-link")) { @@ -1580,6 +1584,7 @@ fn buildOutputType( .linker_z_nodelete = linker_z_nodelete, .linker_z_defs = linker_z_defs, .link_eh_frame_hdr = link_eh_frame_hdr, + .link_emit_relocs = link_emit_relocs, .stack_size_override = stack_size_override, .strip = strip, .single_threaded = single_threaded, From e187ac09cbc23fedef40014f520b2e905033746b Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Sat, 26 Sep 2020 17:40:31 -0600 Subject: [PATCH 26/55] Update compile error tests for alignment in StructField/UnionField --- test/compile_errors.zig | 119 ++++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 60 deletions(-) diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 7c3fa544b6..fef0a64762 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -38,6 +38,61 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:2:20: error: TypeInfo.Enum.tag_type must be an integer type, not 'bool'", }); + cases.add("@Type for tagged union with extra enum field", + \\const TypeInfo = @import("builtin").TypeInfo; + \\const Tag = @Type(.{ + \\ .Enum = .{ + \\ .layout = .Auto, + \\ .tag_type = u2, + \\ .fields = &[_]TypeInfo.EnumField{ + \\ .{ .name = "signed", .value = 0 }, + \\ .{ .name = "unsigned", .value = 1 }, + \\ .{ .name = "arst", .value = 2 }, + \\ }, + \\ .decls = &[_]TypeInfo.Declaration{}, + \\ .is_exhaustive = true, + \\ }, + \\}); + \\const Tagged = @Type(.{ + \\ .Union = .{ + \\ .layout = .Auto, + \\ .tag_type = Tag, + \\ .fields = &[_]TypeInfo.UnionField{ + \\ .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) }, + \\ .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) }, + \\ }, + \\ .decls = &[_]TypeInfo.Declaration{}, + \\ }, + \\}); + \\export fn entry() void { + \\ var tagged = Tagged{ .signed = -1 }; + \\ tagged = .{ .unsigned = 1 }; + \\} + , &[_][]const u8{ + "tmp.zig:15:23: error: enum field missing: 'arst'", + "tmp.zig:27:24: note: referenced here", + }); + + cases.add("@Type for union with opaque field", + \\const TypeInfo = @import("builtin").TypeInfo; + \\const Untagged = @Type(.{ + \\ .Union = .{ + \\ .layout = .Auto, + \\ .tag_type = null, + \\ .fields = &[_]TypeInfo.UnionField{ + \\ .{ .name = "foo", .field_type = @Type(.Opaque), .alignment = 1 }, + \\ }, + \\ .decls = &[_]TypeInfo.Declaration{}, + \\ }, + \\}); + \\export fn entry() void { + \\ _ = Untagged{}; + \\} + , &[_][]const u8{ + "tmp.zig:2:25: error: opaque types have unknown size and therefore cannot be directly embedded in unions", + "tmp.zig:13:17: note: referenced here", + }); + cases.add("slice sentinel mismatch", \\export fn entry() void { \\ const x = @import("std").meta.Vector(3, f32){ 25, 75, 5, 0 }; @@ -54,26 +109,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:2:37: error: expected type '[:1]const u8', found '*const [2:2]u8'", }); - cases.add("@Type for union with opaque field", - \\const TypeInfo = @import("builtin").TypeInfo; - \\const Untagged = @Type(.{ - \\ .Union = .{ - \\ .layout = .Auto, - \\ .tag_type = null, - \\ .fields = &[_]TypeInfo.UnionField{ - \\ .{ .name = "foo", .field_type = @Type(.Opaque) }, - \\ }, - \\ .decls = &[_]TypeInfo.Declaration{}, - \\ }, - \\}); - \\export fn entry() void { - \\ _ = Untagged{}; - \\} - , &[_][]const u8{ - "tmp.zig:2:25: error: opaque types have unknown size and therefore cannot be directly embedded in unions", - "tmp.zig:13:17: note: referenced here", - }); - cases.add("@Type for union with zero fields", \\const TypeInfo = @import("builtin").TypeInfo; \\const Untagged = @Type(.{ @@ -130,9 +165,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ .layout = .Auto, \\ .tag_type = Tag, \\ .fields = &[_]TypeInfo.UnionField{ - \\ .{ .name = "signed", .field_type = i32 }, - \\ .{ .name = "unsigned", .field_type = u32 }, - \\ .{ .name = "arst", .field_type = f32 }, + \\ .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) }, + \\ .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) }, + \\ .{ .name = "arst", .field_type = f32, .alignment = @alignOf(f32) }, \\ }, \\ .decls = &[_]TypeInfo.Declaration{}, \\ }, @@ -147,42 +182,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:27:24: note: referenced here", }); - cases.add("@Type for tagged union with extra enum field", - \\const TypeInfo = @import("builtin").TypeInfo; - \\const Tag = @Type(.{ - \\ .Enum = .{ - \\ .layout = .Auto, - \\ .tag_type = u2, - \\ .fields = &[_]TypeInfo.EnumField{ - \\ .{ .name = "signed", .value = 0 }, - \\ .{ .name = "unsigned", .value = 1 }, - \\ .{ .name = "arst", .field_type = 2 }, - \\ }, - \\ .decls = &[_]TypeInfo.Declaration{}, - \\ .is_exhaustive = true, - \\ }, - \\}); - \\const Tagged = @Type(.{ - \\ .Union = .{ - \\ .layout = .Auto, - \\ .tag_type = Tag, - \\ .fields = &[_]TypeInfo.UnionField{ - \\ .{ .name = "signed", .field_type = i32 }, - \\ .{ .name = "unsigned", .field_type = u32 }, - \\ }, - \\ .decls = &[_]TypeInfo.Declaration{}, - \\ }, - \\}); - \\export fn entry() void { - \\ var tagged = Tagged{ .signed = -1 }; - \\ tagged = .{ .unsigned = 1 }; - \\} - , &[_][]const u8{ - "tmp.zig:9:32: error: no member named 'field_type' in struct 'std.builtin.EnumField'", - "tmp.zig:18:21: note: referenced here", - "tmp.zig:27:18: note: referenced here", - }); - cases.add("@Type with undefined", \\comptime { \\ _ = @Type(.{ .Array = .{ .len = 0, .child = u8, .sentinel = undefined } }); @@ -7592,7 +7591,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { }); cases.add( // fixed bug #2032 - "compile diagnostic string for top level decl type", + "compile diagnostic string for top level decl type", \\export fn entry() void { \\ var foo: u32 = @This(){}; \\} From ec8f0777f23e4585b927c8d95994947b2b263051 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Tue, 29 Sep 2020 10:37:24 -0600 Subject: [PATCH 27/55] Update std.meta.Tuple for alignment in StructField/UnionField --- lib/std/meta.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/std/meta.zig b/lib/std/meta.zig index 492e497ff4..8f40d70fed 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -884,6 +884,7 @@ pub fn Tuple(comptime types: []const type) type { .field_type = T, .default_value = @as(?T, null), .is_comptime = false, + .alignment = @alignOf(T), }; } From 362c87f1aab1db7f0019130115f7cadfef782a56 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Tue, 29 Sep 2020 13:50:43 -0600 Subject: [PATCH 28/55] Update std.meta.ArgsTuple for alignment in StructField/UnionField --- lib/std/meta.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/std/meta.zig b/lib/std/meta.zig index 8f40d70fed..79b0424e96 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -854,6 +854,7 @@ pub fn ArgsTuple(comptime Function: type) type { .field_type = arg.arg_type.?, .default_value = @as(?(arg.arg_type.?), null), .is_comptime = false, + .alignment = @alignOf(arg.arg_type.?), }; } From a4fe438d3940d0beff16c939e991fdff24eb6ba2 Mon Sep 17 00:00:00 2001 From: Alexandros Naskos Date: Fri, 2 Oct 2020 00:39:19 +0300 Subject: [PATCH 29/55] std.fmt.comptimePrint: bufPrint cannot return an error --- lib/std/fmt.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index 0bc5093fb9..ab2cc1577d 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -1183,7 +1183,7 @@ fn bufPrintIntToSlice(buf: []u8, value: anytype, base: u8, uppercase: bool, opti pub fn comptimePrint(comptime fmt: []const u8, args: anytype) *const [count(fmt, args)]u8 { comptime var buf: [count(fmt, args)]u8 = undefined; - _ = bufPrint(&buf, fmt, args) catch |err| @compileError(err); + _ = bufPrint(&buf, fmt, args) catch unreachable; return &buf; } From 5e3ce11b1863b05aba8a2ccadc1140a383ff031a Mon Sep 17 00:00:00 2001 From: Nathan Date: Thu, 1 Oct 2020 17:47:32 -0400 Subject: [PATCH 30/55] Resolve name and format issues. --- lib/std/build.zig | 4 ++-- src/link/Elf.zig | 2 +- src/main.zig | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index 88d416bee6..de93d0bd1c 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -2076,8 +2076,8 @@ pub const LibExeObjStep = struct { if (self.link_eh_frame_hdr) { try zig_args.append("--eh-frame-hdr"); } - if(self.link_emit_relocs){ - try zig_args.append("-emit-relocs"); + if(self.link_emit_relocs) { + try zig_args.append("--emit-relocs"); } if (self.link_function_sections) { try zig_args.append("-ffunction-sections"); diff --git a/src/link/Elf.zig b/src/link/Elf.zig index aab7758505..8e7a02114e 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1367,7 +1367,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { } if (self.base.options.emit_relocs) { - try argv.append("-emit-relocs"); + try argv.append("--emit-relocs"); } if (self.base.options.rdynamic) { diff --git a/src/main.zig b/src/main.zig index d365698d11..d8ca5fe640 100644 --- a/src/main.zig +++ b/src/main.zig @@ -273,7 +273,7 @@ const usage_build_generic = \\ -rdynamic Add all symbols to the dynamic symbol table \\ -rpath [path] Add directory to the runtime library search path \\ --eh-frame-hdr Enable C++ exception handling by passing --eh-frame-hdr to linker - \\ -emit-relocs Enable output of relocation sections for post build tools + \\ --emit-relocs Enable output of relocation sections for post build tools \\ -dynamic Force output to be dynamically linked \\ -static Force output to be statically linked \\ -Bsymbolic Bind global references locally From 84b6d2a80afe26c4b37550c89086cef2f6d066ab Mon Sep 17 00:00:00 2001 From: Nathan Date: Thu, 1 Oct 2020 18:03:34 -0400 Subject: [PATCH 31/55] Resolved additional formatting issues. --- lib/std/build.zig | 2 +- src/main.zig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index de93d0bd1c..27d5f28ac6 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -2076,7 +2076,7 @@ pub const LibExeObjStep = struct { if (self.link_eh_frame_hdr) { try zig_args.append("--eh-frame-hdr"); } - if(self.link_emit_relocs) { + if (self.link_emit_relocs) { try zig_args.append("--emit-relocs"); } if (self.link_function_sections) { diff --git a/src/main.zig b/src/main.zig index d8ca5fe640..f1883230ec 100644 --- a/src/main.zig +++ b/src/main.zig @@ -840,7 +840,7 @@ fn buildOutputType( function_sections = true; } else if (mem.eql(u8, arg, "--eh-frame-hdr")) { link_eh_frame_hdr = true; - } else if (mem.eql(u8, arg, "-emit-relocs")) { + } else if (mem.eql(u8, arg, "--emit-relocs")) { link_emit_relocs = true; } else if (mem.eql(u8, arg, "-Bsymbolic")) { linker_bind_global_refs_locally = true; From 97ab720d84ac6af5174ed93f371fedfa2331445d Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Wed, 23 Sep 2020 11:49:44 -0600 Subject: [PATCH 32/55] stage1: Add alignment to TypeInfo.Fn --- lib/std/builtin.zig | 1 + src/stage1/ir.cpp | 37 +++++++++++++++++------------- test/stage1/behavior/type_info.zig | 6 ++++- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index d80d0e88fe..34452bee09 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -343,6 +343,7 @@ pub const TypeInfo = union(enum) { /// therefore must be kept in sync with the compiler implementation. pub const Fn = struct { calling_convention: CallingConvention, + alignment: u29, is_generic: bool, is_var_args: bool, return_type: ?type, diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp index 8da207cab7..6d309ef16b 100644 --- a/src/stage1/ir.cpp +++ b/src/stage1/ir.cpp @@ -25564,7 +25564,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy result->special = ConstValSpecialStatic; result->type = ir_type_info_get_type(ira, "Fn", nullptr); - ZigValue **fields = alloc_const_vals_ptrs(ira->codegen, 5); + ZigValue **fields = alloc_const_vals_ptrs(ira->codegen, 6); result->data.x_struct.fields = fields; // calling_convention: TypeInfo.CallingConvention @@ -25572,30 +25572,35 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy fields[0]->special = ConstValSpecialStatic; fields[0]->type = get_builtin_type(ira->codegen, "CallingConvention"); bigint_init_unsigned(&fields[0]->data.x_enum_tag, type_entry->data.fn.fn_type_id.cc); - // is_generic: bool - ensure_field_index(result->type, "is_generic", 1); - bool is_generic = type_entry->data.fn.is_generic; + // alignment: u29 + ensure_field_index(result->type, "alignment", 1); fields[1]->special = ConstValSpecialStatic; - fields[1]->type = ira->codegen->builtin_types.entry_bool; - fields[1]->data.x_bool = is_generic; - // is_varargs: bool - ensure_field_index(result->type, "is_var_args", 2); - bool is_varargs = type_entry->data.fn.fn_type_id.is_var_args; + fields[1]->type = ira->codegen->builtin_types.entry_u29; + bigint_init_unsigned(&fields[1]->data.x_bigint, type_entry->data.fn.fn_type_id.alignment); + // is_generic: bool + ensure_field_index(result->type, "is_generic", 2); + bool is_generic = type_entry->data.fn.is_generic; fields[2]->special = ConstValSpecialStatic; fields[2]->type = ira->codegen->builtin_types.entry_bool; - fields[2]->data.x_bool = type_entry->data.fn.fn_type_id.is_var_args; - // return_type: ?type - ensure_field_index(result->type, "return_type", 3); + fields[2]->data.x_bool = is_generic; + // is_varargs: bool + ensure_field_index(result->type, "is_var_args", 3); + bool is_varargs = type_entry->data.fn.fn_type_id.is_var_args; fields[3]->special = ConstValSpecialStatic; - fields[3]->type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type); + fields[3]->type = ira->codegen->builtin_types.entry_bool; + fields[3]->data.x_bool = is_varargs; + // return_type: ?type + ensure_field_index(result->type, "return_type", 4); + fields[4]->special = ConstValSpecialStatic; + fields[4]->type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type); if (type_entry->data.fn.fn_type_id.return_type == nullptr) - fields[3]->data.x_optional = nullptr; + fields[4]->data.x_optional = nullptr; else { ZigValue *return_type = ira->codegen->pass1_arena->create(); return_type->special = ConstValSpecialStatic; return_type->type = ira->codegen->builtin_types.entry_type; return_type->data.x_type = type_entry->data.fn.fn_type_id.return_type; - fields[3]->data.x_optional = return_type; + fields[4]->data.x_optional = return_type; } // args: []TypeInfo.FnArg ZigType *type_info_fn_arg_type = ir_type_info_get_type(ira, "FnArg", nullptr); @@ -25611,7 +25616,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy fn_arg_array->data.x_array.special = ConstArraySpecialNone; fn_arg_array->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(fn_arg_count); - init_const_slice(ira->codegen, fields[4], fn_arg_array, 0, fn_arg_count, false); + init_const_slice(ira->codegen, fields[5], fn_arg_array, 0, fn_arg_count, false); for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++) { FnTypeParamInfo *fn_param_info = &type_entry->data.fn.fn_type_id.param_info[fn_arg_index]; diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig index f5b37fe3f0..bb6dede96d 100644 --- a/test/stage1/behavior/type_info.zig +++ b/test/stage1/behavior/type_info.zig @@ -273,11 +273,14 @@ test "type info: function type info" { fn testFunction() void { const fn_info = @typeInfo(@TypeOf(foo)); expect(fn_info == .Fn); + expect(fn_info.Fn.alignment == 0); expect(fn_info.Fn.calling_convention == .C); expect(!fn_info.Fn.is_generic); expect(fn_info.Fn.args.len == 2); expect(fn_info.Fn.is_var_args); expect(fn_info.Fn.return_type.? == usize); + const fn_aligned_info = @typeInfo(@TypeOf(fooAligned)); + expect(fn_aligned_info.Fn.alignment == 4); const test_instance: TestStruct = undefined; const bound_fn_info = @typeInfo(@TypeOf(test_instance.foo)); @@ -285,7 +288,8 @@ fn testFunction() void { expect(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct); } -extern fn foo(a: usize, b: bool, ...) usize; +extern fn foo(a: usize, b: bool, ...) callconv(.C) usize; +extern fn fooAligned(a: usize, b: bool, ...) align(4) callconv(.C) usize; test "typeInfo with comptime parameter in struct fn def" { const S = struct { From e18fdc12b06cb904814700a96dce5ba419d08364 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Wed, 23 Sep 2020 13:12:26 -0600 Subject: [PATCH 33/55] stage1: Implement @Type for Fn and BoundFn --- src/stage1/ir.cpp | 117 ++++++++++++++++++++++++++++++++-- test/compile_errors.zig | 47 ++++++++++++++ test/stage1/behavior/type.zig | 21 ++++++ 3 files changed, 179 insertions(+), 6 deletions(-) diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp index 6d309ef16b..162fa1bea5 100644 --- a/src/stage1/ir.cpp +++ b/src/stage1/ir.cpp @@ -25607,8 +25607,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy if ((err = type_resolve(ira->codegen, type_info_fn_arg_type, ResolveStatusSizeKnown))) { zig_unreachable(); } - size_t fn_arg_count = type_entry->data.fn.fn_type_id.param_count - - (is_varargs && type_entry->data.fn.fn_type_id.cc != CallingConventionC); + size_t fn_arg_count = type_entry->data.fn.fn_type_id.param_count; ZigValue *fn_arg_array = ira->codegen->pass1_arena->create(); fn_arg_array->special = ConstValSpecialStatic; @@ -25757,6 +25756,17 @@ static Error get_const_field_bool(IrAnalyze *ira, AstNode *source_node, ZigValue return ErrorNone; } +static Error get_const_field_u29(IrAnalyze *ira, AstNode *source_node, ZigValue *struct_value, + const char *name, size_t field_index, uint32_t *out) +{ + ZigValue *value = get_const_field(ira, source_node, struct_value, name, field_index); + if (value == nullptr) + return ErrorSemanticAnalyzeFail; + assert(value->type == ira->codegen->builtin_types.entry_u29); + *out = bigint_as_u32(&value->data.x_bigint); + return ErrorNone; +} + static BigInt *get_const_field_lit_int(IrAnalyze *ira, AstNode *source_node, ZigValue *struct_value, const char *name, size_t field_index) { ZigValue *value = get_const_field(ira, source_node, struct_value, name, field_index); @@ -26332,10 +26342,105 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI return entry; } case ZigTypeIdFn: - case ZigTypeIdBoundFn: - ir_add_error(ira, source_instr, buf_sprintf( - "@Type not available for 'TypeInfo.%s'", type_id_name(tagTypeId))); - return ira->codegen->invalid_inst_gen->value->type; + case ZigTypeIdBoundFn: { + assert(payload->special == ConstValSpecialStatic); + assert(payload->type == ir_type_info_get_type(ira, "Fn", nullptr)); + + ZigValue *cc_value = get_const_field(ira, source_instr->source_node, payload, "calling_convention", 0); + if (cc_value == nullptr) + return ira->codegen->invalid_inst_gen->value->type; + assert(cc_value->special == ConstValSpecialStatic); + assert(cc_value->type == get_builtin_type(ira->codegen, "CallingConvention")); + CallingConvention cc = (CallingConvention)bigint_as_u32(&cc_value->data.x_enum_tag); + + uint32_t alignment; + if ((err = get_const_field_u29(ira, source_instr->source_node, payload, "alignment", 1, &alignment))) + return ira->codegen->invalid_inst_gen->value->type; + + Error err; + bool is_generic; + if ((err = get_const_field_bool(ira, source_instr->source_node, payload, "is_generic", 2, &is_generic))) + return ira->codegen->invalid_inst_gen->value->type; + if (is_generic) { + ir_add_error(ira, source_instr, buf_sprintf("TypeInfo.Fn.is_generic must be false for @Type")); + return ira->codegen->invalid_inst_gen->value->type; + } + + bool is_var_args; + if ((err = get_const_field_bool(ira, source_instr->source_node, payload, "is_var_args", 3, &is_var_args))) + return ira->codegen->invalid_inst_gen->value->type; + if (is_var_args && cc != CallingConventionC) { + ir_add_error(ira, source_instr, buf_sprintf("varargs functions must have C calling convention")); + return ira->codegen->invalid_inst_gen->value->type; + } + + ZigType *return_type = get_const_field_meta_type_optional(ira, source_instr->source_node, payload, "return_type", 4); + if (return_type == nullptr) { + ir_add_error(ira, source_instr, buf_sprintf("TypeInfo.Fn.return_type must be non-null for @Type")); + return ira->codegen->invalid_inst_gen->value->type; + } + + ZigValue *args_value = get_const_field(ira, source_instr->source_node, payload, "args", 5); + if (args_value == nullptr) + return ira->codegen->invalid_inst_gen->value->type; + assert(args_value->special == ConstValSpecialStatic); + assert(is_slice(args_value->type)); + ZigValue *args_ptr = args_value->data.x_struct.fields[slice_ptr_index]; + ZigValue *args_len_value = args_value->data.x_struct.fields[slice_len_index]; + size_t args_len = bigint_as_usize(&args_len_value->data.x_bigint); + + FnTypeId fn_type_id = {}; + fn_type_id.return_type = return_type; + fn_type_id.param_info = heap::c_allocator.allocate(args_len); + fn_type_id.param_count = args_len; + fn_type_id.next_param_index = args_len; + fn_type_id.is_var_args = is_var_args; + fn_type_id.cc = cc; + fn_type_id.alignment = alignment; + + assert(args_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray); + assert(args_ptr->data.x_ptr.data.base_array.elem_index == 0); + ZigValue *args_arr = args_ptr->data.x_ptr.data.base_array.array_val; + assert(args_arr->special == ConstValSpecialStatic); + assert(args_arr->data.x_array.special == ConstArraySpecialNone); + for (size_t i = 0; i < args_len; i++) { + ZigValue *arg_value = &args_arr->data.x_array.data.s_none.elements[i]; + assert(arg_value->type == ir_type_info_get_type(ira, "FnArg", nullptr)); + FnTypeParamInfo *info = &fn_type_id.param_info[i]; + Error err; + bool is_generic; + if ((err = get_const_field_bool(ira, source_instr->source_node, arg_value, "is_generic", 0, &is_generic))) + return ira->codegen->invalid_inst_gen->value->type; + if (is_generic) { + ir_add_error(ira, source_instr, buf_sprintf("TypeInfo.FnArg.is_generic must be false for @Type")); + return ira->codegen->invalid_inst_gen->value->type; + } + if ((err = get_const_field_bool(ira, source_instr->source_node, arg_value, "is_noalias", 1, &info->is_noalias))) + return ira->codegen->invalid_inst_gen->value->type; + ZigType *type = get_const_field_meta_type_optional( + ira, source_instr->source_node, arg_value, "arg_type", 2); + if (type == nullptr) { + ir_add_error(ira, source_instr, buf_sprintf("TypeInfo.FnArg.arg_type must be non-null for @Type")); + return ira->codegen->invalid_inst_gen->value->type; + } + info->type = type; + } + + ZigType *entry = get_fn_type(ira->codegen, &fn_type_id); + + switch (tagTypeId) { + case ZigTypeIdFn: + return entry; + case ZigTypeIdBoundFn: { + ZigType *bound_fn_entry = new_type_table_entry(ZigTypeIdBoundFn); + bound_fn_entry->name = *buf_sprintf("(bound %s)", buf_ptr(&entry->name)); + bound_fn_entry->data.bound_fn.fn_type = entry; + return bound_fn_entry; + } + default: + zig_unreachable(); + } + } } zig_unreachable(); } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index fef0a64762..b1e23d40cb 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -72,6 +72,53 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:15:23: error: enum field missing: 'arst'", "tmp.zig:27:24: note: referenced here", }); + cases.add("@Type(.Fn) with is_generic = true", + \\const Foo = @Type(.{ + \\ .Fn = .{ + \\ .calling_convention = .Unspecified, + \\ .alignment = 0, + \\ .is_generic = true, + \\ .is_var_args = false, + \\ .return_type = u0, + \\ .args = &[_]@import("builtin").TypeInfo.FnArg{}, + \\ }, + \\}); + \\comptime { _ = Foo; } + , &[_][]const u8{ + "tmp.zig:1:20: error: TypeInfo.Fn.is_generic must be false for @Type", + }); + + cases.add("@Type(.Fn) with is_var_args = true and non-C callconv", + \\const Foo = @Type(.{ + \\ .Fn = .{ + \\ .calling_convention = .Unspecified, + \\ .alignment = 0, + \\ .is_generic = false, + \\ .is_var_args = true, + \\ .return_type = u0, + \\ .args = &[_]@import("builtin").TypeInfo.FnArg{}, + \\ }, + \\}); + \\comptime { _ = Foo; } + , &[_][]const u8{ + "tmp.zig:1:20: error: varargs functions must have C calling convention", + }); + + cases.add("@Type(.Fn) with return_type = null", + \\const Foo = @Type(.{ + \\ .Fn = .{ + \\ .calling_convention = .Unspecified, + \\ .alignment = 0, + \\ .is_generic = false, + \\ .is_var_args = false, + \\ .return_type = null, + \\ .args = &[_]@import("builtin").TypeInfo.FnArg{}, + \\ }, + \\}); + \\comptime { _ = Foo; } + , &[_][]const u8{ + "tmp.zig:1:20: error: TypeInfo.Fn.return_type must be non-null for @Type", + }); cases.add("@Type for union with opaque field", \\const TypeInfo = @import("builtin").TypeInfo; diff --git a/test/stage1/behavior/type.zig b/test/stage1/behavior/type.zig index 1bb0823e74..936ed0486c 100644 --- a/test/stage1/behavior/type.zig +++ b/test/stage1/behavior/type.zig @@ -416,3 +416,24 @@ test "Type.Union from regular enum" { _ = T; _ = @typeInfo(T).Union; } + +test "Type.Fn" { + const foo = struct { + fn func(a: usize, b: bool) align(4) callconv(.C) usize { + return 0; + } + }.func; + const Foo = @Type(@typeInfo(@TypeOf(foo))); + const foo_2: Foo = foo; +} + +test "Type.BoundFn" { + const TestStruct = packed struct { + pub fn foo(self: *const @This()) align(4) callconv(.Unspecified) void {} + }; + const test_instance: TestStruct = undefined; + testing.expect(std.meta.eql( + @typeName(@TypeOf(test_instance.foo)), + @typeName(@Type(@typeInfo(@TypeOf(test_instance.foo)))), + )); +} From 96a151d4b83ea4148db4d13b5576897645209f46 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Thu, 24 Sep 2020 05:03:19 -0600 Subject: [PATCH 34/55] Skip @Type/@typeInfo Fn/BoundFn tests on wasm32/wasm64 --- test/stage1/behavior/type.zig | 6 ++++++ test/stage1/behavior/type_info.zig | 2 ++ 2 files changed, 8 insertions(+) diff --git a/test/stage1/behavior/type.zig b/test/stage1/behavior/type.zig index 936ed0486c..60a23ffa94 100644 --- a/test/stage1/behavior/type.zig +++ b/test/stage1/behavior/type.zig @@ -418,6 +418,9 @@ test "Type.Union from regular enum" { } test "Type.Fn" { + // wasm doesn't support align attributes on functions + if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest; + const foo = struct { fn func(a: usize, b: bool) align(4) callconv(.C) usize { return 0; @@ -428,6 +431,9 @@ test "Type.Fn" { } test "Type.BoundFn" { + // wasm doesn't support align attributes on functions + if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest; + const TestStruct = packed struct { pub fn foo(self: *const @This()) align(4) callconv(.Unspecified) void {} }; diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig index bb6dede96d..8b413bf031 100644 --- a/test/stage1/behavior/type_info.zig +++ b/test/stage1/behavior/type_info.zig @@ -266,6 +266,8 @@ const TestStruct = packed struct { }; test "type info: function type info" { + // wasm doesn't support align attributes on functions + if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest; testFunction(); comptime testFunction(); } From 183d1d4ba1a855cc85ac93f51dec5f4b2301ce1d Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Sat, 26 Sep 2020 12:00:41 -0600 Subject: [PATCH 35/55] Switch TypeInfo.Fn.alignment to comptime_int from u29 All integers in TypeInfo are intentionally comptime_int: https://github.com/ziglang/zig/issues/1683 --- lib/std/builtin.zig | 2 +- src/stage1/ir.cpp | 19 ++++--------------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 34452bee09..92fa78bc39 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -343,7 +343,7 @@ pub const TypeInfo = union(enum) { /// therefore must be kept in sync with the compiler implementation. pub const Fn = struct { calling_convention: CallingConvention, - alignment: u29, + alignment: comptime_int, is_generic: bool, is_var_args: bool, return_type: ?type, diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp index 162fa1bea5..045f1ad784 100644 --- a/src/stage1/ir.cpp +++ b/src/stage1/ir.cpp @@ -25575,7 +25575,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy // alignment: u29 ensure_field_index(result->type, "alignment", 1); fields[1]->special = ConstValSpecialStatic; - fields[1]->type = ira->codegen->builtin_types.entry_u29; + fields[1]->type = ira->codegen->builtin_types.entry_num_lit_int; bigint_init_unsigned(&fields[1]->data.x_bigint, type_entry->data.fn.fn_type_id.alignment); // is_generic: bool ensure_field_index(result->type, "is_generic", 2); @@ -25756,17 +25756,6 @@ static Error get_const_field_bool(IrAnalyze *ira, AstNode *source_node, ZigValue return ErrorNone; } -static Error get_const_field_u29(IrAnalyze *ira, AstNode *source_node, ZigValue *struct_value, - const char *name, size_t field_index, uint32_t *out) -{ - ZigValue *value = get_const_field(ira, source_node, struct_value, name, field_index); - if (value == nullptr) - return ErrorSemanticAnalyzeFail; - assert(value->type == ira->codegen->builtin_types.entry_u29); - *out = bigint_as_u32(&value->data.x_bigint); - return ErrorNone; -} - static BigInt *get_const_field_lit_int(IrAnalyze *ira, AstNode *source_node, ZigValue *struct_value, const char *name, size_t field_index) { ZigValue *value = get_const_field(ira, source_node, struct_value, name, field_index); @@ -26353,8 +26342,8 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI assert(cc_value->type == get_builtin_type(ira->codegen, "CallingConvention")); CallingConvention cc = (CallingConvention)bigint_as_u32(&cc_value->data.x_enum_tag); - uint32_t alignment; - if ((err = get_const_field_u29(ira, source_instr->source_node, payload, "alignment", 1, &alignment))) + BigInt *alignment = get_const_field_lit_int(ira, source_instr->source_node, payload, "alignment", 1); + if (alignment == nullptr) return ira->codegen->invalid_inst_gen->value->type; Error err; @@ -26396,7 +26385,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI fn_type_id.next_param_index = args_len; fn_type_id.is_var_args = is_var_args; fn_type_id.cc = cc; - fn_type_id.alignment = alignment; + fn_type_id.alignment = bigint_as_u32(alignment); assert(args_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray); assert(args_ptr->data.x_ptr.data.base_array.elem_index == 0); From 61ce72a38cedfcbd8450922cbf1cadc0c1682928 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Sat, 26 Sep 2020 08:01:09 -0600 Subject: [PATCH 36/55] Allow enums with explicit extern-allowed tag types in extern types Closes https://github.com/ziglang/zig/issues/1467 --- src/stage1/all_types.hpp | 1 + src/stage1/analyze.cpp | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/stage1/all_types.hpp b/src/stage1/all_types.hpp index 7a5016d004..9f289a8f64 100644 --- a/src/stage1/all_types.hpp +++ b/src/stage1/all_types.hpp @@ -1456,6 +1456,7 @@ struct ZigTypeEnum { ContainerLayout layout; ResolveStatus resolve_status; + bool has_explicit_tag_type; bool non_exhaustive; bool resolve_loop_flag; }; diff --git a/src/stage1/analyze.cpp b/src/stage1/analyze.cpp index 369c284684..64251c1f0c 100644 --- a/src/stage1/analyze.cpp +++ b/src/stage1/analyze.cpp @@ -1802,10 +1802,18 @@ Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, bool *result) { } return type_allowed_in_extern(g, child_type, result); } - case ZigTypeIdEnum: - *result = type_entry->data.enumeration.layout == ContainerLayoutExtern || - type_entry->data.enumeration.layout == ContainerLayoutPacked; - return ErrorNone; + case ZigTypeIdEnum: { + if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) + return err; + ZigType *tag_int_type = type_entry->data.enumeration.tag_int_type; + if (type_entry->data.enumeration.has_explicit_tag_type) { + return type_allowed_in_extern(g, tag_int_type, result); + } else { + *result = type_entry->data.enumeration.layout == ContainerLayoutExtern || + type_entry->data.enumeration.layout == ContainerLayoutPacked; + return ErrorNone; + } + } case ZigTypeIdUnion: *result = type_entry->data.unionation.layout == ContainerLayoutExtern || type_entry->data.unionation.layout == ContainerLayoutPacked; @@ -2639,9 +2647,11 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { if (decl_node->type == NodeTypeContainerDecl) { if (decl_node->data.container_decl.init_arg_expr != nullptr) { wanted_tag_int_type = analyze_type_expr(g, scope, decl_node->data.container_decl.init_arg_expr); + enum_type->data.enumeration.has_explicit_tag_type = true; } } else { wanted_tag_int_type = enum_type->data.enumeration.tag_int_type; + enum_type->data.enumeration.has_explicit_tag_type = true; } if (wanted_tag_int_type != nullptr) { From cae49b1b9d40e106f52c8f80c00019138961bf89 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Sat, 26 Sep 2020 08:06:14 -0600 Subject: [PATCH 37/55] Add tests for enums with explicit extern-allowed tag types in extern types --- test/compile_errors.zig | 12 ++++++++++++ test/stage1/behavior/bugs/1467.zig | 7 +++++++ 2 files changed, 19 insertions(+) create mode 100644 test/stage1/behavior/bugs/1467.zig diff --git a/test/compile_errors.zig b/test/compile_errors.zig index fef0a64762..90ed504eac 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -20,6 +20,18 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:2:20: error: use of undefined value here causes undefined behavior", }); + cases.add("extern struct with non-extern-compatible integer tag type", + \\pub const E = enum(u31) { A, B, C }; + \\pub const S = extern struct { + \\ e: E, + \\}; + \\export fn entry() void { + \\ const s: S = undefined; + \\} + , &[_][]const u8{ + "tmp.zig:3:5: error: extern structs cannot contain fields of type 'E'", + }); + cases.add("@Type for exhaustive enum with non-integer tag type", \\const TypeInfo = @import("builtin").TypeInfo; \\const Tag = @Type(.{ diff --git a/test/stage1/behavior/bugs/1467.zig b/test/stage1/behavior/bugs/1467.zig new file mode 100644 index 0000000000..71c55dc59c --- /dev/null +++ b/test/stage1/behavior/bugs/1467.zig @@ -0,0 +1,7 @@ +pub const E = enum(u32) { A, B, C }; +pub const S = extern struct { + e: E, +}; +test "bug 1467" { + const s: S = undefined; +} From 65016dff322c9344cc5e7bf9d6ad6907de940c7f Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Sat, 26 Sep 2020 08:21:27 -0600 Subject: [PATCH 38/55] Add test for implicit extern-allowed enum tag type in extern struct --- test/compile_errors.zig | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 90ed504eac..d3be0e060b 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -50,6 +50,47 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:2:20: error: TypeInfo.Enum.tag_type must be an integer type, not 'bool'", }); + cases.add("extern struct with extern-compatible but inferred integer tag type", + \\pub const E = enum { + \\@"0",@"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",@"10",@"11",@"12", + \\@"13",@"14",@"15",@"16",@"17",@"18",@"19",@"20",@"21",@"22",@"23", + \\@"24",@"25",@"26",@"27",@"28",@"29",@"30",@"31",@"32",@"33",@"34", + \\@"35",@"36",@"37",@"38",@"39",@"40",@"41",@"42",@"43",@"44",@"45", + \\@"46",@"47",@"48",@"49",@"50",@"51",@"52",@"53",@"54",@"55",@"56", + \\@"57",@"58",@"59",@"60",@"61",@"62",@"63",@"64",@"65",@"66",@"67", + \\@"68",@"69",@"70",@"71",@"72",@"73",@"74",@"75",@"76",@"77",@"78", + \\@"79",@"80",@"81",@"82",@"83",@"84",@"85",@"86",@"87",@"88",@"89", + \\@"90",@"91",@"92",@"93",@"94",@"95",@"96",@"97",@"98",@"99",@"100", + \\@"101",@"102",@"103",@"104",@"105",@"106",@"107",@"108",@"109", + \\@"110",@"111",@"112",@"113",@"114",@"115",@"116",@"117",@"118", + \\@"119",@"120",@"121",@"122",@"123",@"124",@"125",@"126",@"127", + \\@"128",@"129",@"130",@"131",@"132",@"133",@"134",@"135",@"136", + \\@"137",@"138",@"139",@"140",@"141",@"142",@"143",@"144",@"145", + \\@"146",@"147",@"148",@"149",@"150",@"151",@"152",@"153",@"154", + \\@"155",@"156",@"157",@"158",@"159",@"160",@"161",@"162",@"163", + \\@"164",@"165",@"166",@"167",@"168",@"169",@"170",@"171",@"172", + \\@"173",@"174",@"175",@"176",@"177",@"178",@"179",@"180",@"181", + \\@"182",@"183",@"184",@"185",@"186",@"187",@"188",@"189",@"190", + \\@"191",@"192",@"193",@"194",@"195",@"196",@"197",@"198",@"199", + \\@"200",@"201",@"202",@"203",@"204",@"205",@"206",@"207",@"208", + \\@"209",@"210",@"211",@"212",@"213",@"214",@"215",@"216",@"217", + \\@"218",@"219",@"220",@"221",@"222",@"223",@"224",@"225",@"226", + \\@"227",@"228",@"229",@"230",@"231",@"232",@"233",@"234",@"235", + \\@"236",@"237",@"238",@"239",@"240",@"241",@"242",@"243",@"244", + \\@"245",@"246",@"247",@"248",@"249",@"250",@"251",@"252",@"253", + \\@"254",@"255" + \\}; + \\pub const S = extern struct { + \\ e: E, + \\}; + \\export fn entry() void { + \\ if (@TagType(E) != u8) @compileError("did not infer u8 tag type"); + \\ const s: S = undefined; + \\} + , &[_][]const u8{ + "tmp.zig:31:5: error: extern structs cannot contain fields of type 'E'", + }); + cases.add("@Type for tagged union with extra enum field", \\const TypeInfo = @import("builtin").TypeInfo; \\const Tag = @Type(.{ From a2074c1ec31ab553aea4232dfdc760a0442aeddf Mon Sep 17 00:00:00 2001 From: Loris Cro Date: Fri, 2 Oct 2020 17:06:29 +0200 Subject: [PATCH 39/55] fix symlink path not being resolved in darwin Signed-off-by: Loris Cro --- lib/std/fs.zig | 16 ++++++++++++---- lib/std/os.zig | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 1890d7e136..fcd1ce72c8 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -2162,7 +2162,7 @@ pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File { return openFileAbsoluteZ(buf[0..self_exe_path.len :0].ptr, flags); } -pub const SelfExePathError = os.ReadLinkError || os.SysCtlError; +pub const SelfExePathError = os.ReadLinkError || os.SysCtlError || os.RealPathError; /// `selfExePath` except allocates the result on the heap. /// Caller owns returned memory. @@ -2190,10 +2190,18 @@ pub fn selfExePathAlloc(allocator: *Allocator) ![]u8 { /// TODO make the return type of this a null terminated pointer pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 { if (is_darwin) { - var u32_len: u32 = @intCast(u32, math.min(out_buffer.len, math.maxInt(u32))); - const rc = std.c._NSGetExecutablePath(out_buffer.ptr, &u32_len); + // Note that _NSGetExecutablePath() will return "a path" to + // the executable not a "real path" to the executable. + var symlink_path_buf: [MAX_PATH_BYTES]u8 = undefined; + var u32_len: u32 = MAX_PATH_BYTES; + const rc = std.c._NSGetExecutablePath(&symlink_path_buf, &u32_len); if (rc != 0) return error.NameTooLong; - return mem.spanZ(@ptrCast([*:0]u8, out_buffer)); + + var real_path_buf: [MAX_PATH_BYTES]u8 = undefined; + const real_path = try std.os.realpathZ(@ptrCast([*:0]u8, &symlink_path_buf), &real_path_buf); + if (real_path.len > out_buffer.len) return error.NameTooLong; + std.mem.copy(u8, out_buffer, real_path); + return out_buffer[0..real_path.len]; } switch (builtin.os.tag) { .linux => return os.readlinkZ("/proc/self/exe", out_buffer), diff --git a/lib/std/os.zig b/lib/std/os.zig index c06ce4ed00..ef342edf56 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -3993,7 +3993,7 @@ pub const RealPathError = error{ /// Expands all symbolic links and resolves references to `.`, `..`, and /// extra `/` characters in `pathname`. /// The return value is a slice of `out_buffer`, but not necessarily from the beginning. -/// See also `realpathC` and `realpathW`. +/// See also `realpathZ` and `realpathW`. pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { if (builtin.os.tag == .windows) { const pathname_w = try windows.sliceToPrefixedFileW(pathname); From f841ea77e2cb7ad2ee4ecf993206f0c29d087131 Mon Sep 17 00:00:00 2001 From: Loris Cro Date: Fri, 2 Oct 2020 19:33:14 +0200 Subject: [PATCH 40/55] make symlink buffer null-terminated Signed-off-by: Loris Cro --- lib/std/c/darwin.zig | 2 +- lib/std/fs.zig | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig index ed1ddb7d91..976690d6b7 100644 --- a/lib/std/c/darwin.zig +++ b/lib/std/c/darwin.zig @@ -12,7 +12,7 @@ usingnamespace @import("../os/bits.zig"); extern "c" fn __error() *c_int; pub extern "c" fn NSVersionOfRunTimeLibrary(library_name: [*:0]const u8) u32; -pub extern "c" fn _NSGetExecutablePath(buf: [*]u8, bufsize: *u32) c_int; +pub extern "c" fn _NSGetExecutablePath(buf: [*:0]u8, bufsize: *u32) c_int; pub extern "c" fn _dyld_image_count() u32; pub extern "c" fn _dyld_get_image_header(image_index: u32) ?*mach_header; pub extern "c" fn _dyld_get_image_vmaddr_slide(image_index: u32) usize; diff --git a/lib/std/fs.zig b/lib/std/fs.zig index fcd1ce72c8..51d40caf56 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -2192,13 +2192,13 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 { if (is_darwin) { // Note that _NSGetExecutablePath() will return "a path" to // the executable not a "real path" to the executable. - var symlink_path_buf: [MAX_PATH_BYTES]u8 = undefined; + var symlink_path_buf: [MAX_PATH_BYTES:0]u8 = undefined; var u32_len: u32 = MAX_PATH_BYTES; const rc = std.c._NSGetExecutablePath(&symlink_path_buf, &u32_len); if (rc != 0) return error.NameTooLong; var real_path_buf: [MAX_PATH_BYTES]u8 = undefined; - const real_path = try std.os.realpathZ(@ptrCast([*:0]u8, &symlink_path_buf), &real_path_buf); + const real_path = try std.os.realpathZ(&symlink_path_buf, &real_path_buf); if (real_path.len > out_buffer.len) return error.NameTooLong; std.mem.copy(u8, out_buffer, real_path); return out_buffer[0..real_path.len]; From 539e90e26d86b7e8fbc81f069a062beb7a43edb3 Mon Sep 17 00:00:00 2001 From: Timon Kruiper Date: Fri, 2 Oct 2020 19:59:00 +0200 Subject: [PATCH 41/55] Print error when running `zig test/run` without a source file Closes #6498 --- src/main.zig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main.zig b/src/main.zig index f1883230ec..d1017a911d 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1210,6 +1210,10 @@ fn buildOutputType( fatal("translate-c expects exactly 1 source file (found {})", .{c_source_files.items.len}); } + if (root_src_file == null and (arg_mode == .zig_test or arg_mode == .run)) { + fatal("one zig source file is required to run this command", .{}); + } + const root_name = if (provided_name) |n| n else blk: { if (arg_mode == .zig_test) { break :blk "test"; From 276598346a1f04bcfbe4982ea3c766aa79cad681 Mon Sep 17 00:00:00 2001 From: Loris Cro Date: Sat, 3 Oct 2020 12:03:22 +0200 Subject: [PATCH 42/55] provide the full buffer length to _NSGetExecutablePath Signed-off-by: Loris Cro --- lib/std/fs.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 51d40caf56..1d98c03c5c 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -2193,7 +2193,7 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 { // Note that _NSGetExecutablePath() will return "a path" to // the executable not a "real path" to the executable. var symlink_path_buf: [MAX_PATH_BYTES:0]u8 = undefined; - var u32_len: u32 = MAX_PATH_BYTES; + var u32_len: u32 = MAX_PATH_BYTES + 1; // include the sentinel const rc = std.c._NSGetExecutablePath(&symlink_path_buf, &u32_len); if (rc != 0) return error.NameTooLong; From 3b40b682102917955af0939d6c78bdb16ddd78e7 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 3 Oct 2020 20:47:06 +0200 Subject: [PATCH 43/55] stage2: Build libunwind for non-msvc Windows targets Closes #6497 --- src/target.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target.zig b/src/target.zig index fc0c7a0745..d009cf8556 100644 --- a/src/target.zig +++ b/src/target.zig @@ -130,7 +130,6 @@ pub fn osRequiresLibC(target: std.Target) bool { pub fn libcNeedsLibUnwind(target: std.Target) bool { return switch (target.os.tag) { - .windows, .macosx, .ios, .watchos, @@ -138,6 +137,7 @@ pub fn libcNeedsLibUnwind(target: std.Target) bool { .freestanding, => false, + .windows => target.abi != .msvc, else => true, }; } From 70f37679035e64bacfc4807709da37bc02fbb346 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 3 Oct 2020 17:13:22 -0700 Subject: [PATCH 44/55] revert adding std.event.Loop.runDetached I'd like to discuss this before adding it. I think this is the wrong direction to go with this API. --- lib/std/event/loop.zig | 53 ------------------------------------------ 1 file changed, 53 deletions(-) diff --git a/lib/std/event/loop.zig b/lib/std/event/loop.zig index cf220bf775..2ed9f938d8 100644 --- a/lib/std/event/loop.zig +++ b/lib/std/event/loop.zig @@ -647,29 +647,6 @@ pub const Loop = struct { } } - /// Runs the provided function asynchonously, similarly to Go's "go" operator. - /// `func` must return void and it can be an async function. - pub fn runDetached(self: *Loop, alloc: *mem.Allocator, comptime func: anytype, args: anytype) error{OutOfMemory}!void { - if (!std.io.is_async) @compileError("Can't use runDetached in non-async mode!"); - if (@TypeOf(@call(.{}, func, args)) != void) { - @compileError("`func` must not have a return value"); - } - - const Wrapper = struct { - const Args = @TypeOf(args); - fn run(func_args: Args, loop: *Loop, allocator: *mem.Allocator) void { - loop.yield(); - const result = @call(.{}, func, func_args); - suspend { - allocator.destroy(@frame()); - } - } - }; - - var run_frame = try alloc.create(@Frame(Wrapper.run)); - run_frame.* = async Wrapper.run(args, self, alloc); - } - /// Yielding lets the event loop run, starting any unstarted async operations. /// Note that async operations automatically start when a function yields for any other reason, /// for example, when async I/O is performed. This function is intended to be used only when @@ -1516,33 +1493,3 @@ fn testEventLoop2(h: anyframe->i32, did_it: *bool) void { testing.expect(value == 1234); did_it.* = true; } - -var testRunDetachedData: usize = 0; -test "std.event.Loop - runDetached" { - // https://github.com/ziglang/zig/issues/1908 - if (builtin.single_threaded) return error.SkipZigTest; - if (!std.io.is_async) return error.SkipZigTest; - if (true) { - // https://github.com/ziglang/zig/issues/4922 - return error.SkipZigTest; - } - - var loop: Loop = undefined; - try loop.initMultiThreaded(); - defer loop.deinit(); - - // Schedule the execution, won't actually start until we start the - // event loop. - try loop.runDetached(std.testing.allocator, testRunDetached, .{}); - - // Now we can start the event loop. The function will return only - // after all tasks have been completed, allowing us to synchonize - // with the previous runDetached. - loop.run(); - - testing.expect(testRunDetachedData == 1); -} - -fn testRunDetached() void { - testRunDetachedData += 1; -} From 0e7523c7d7eb42a5927be4de897ab623f033d2fe Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 3 Oct 2020 17:16:19 -0700 Subject: [PATCH 45/55] stage1 main(): catch unreachable in debug builds for easier troubleshooting Fixup to 2a3393eff853fe0a1dee766c859a345186e91fa3 --- src/stage1.zig | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/stage1.zig b/src/stage1.zig index 10b85899c2..f26622ee89 100644 --- a/src/stage1.zig +++ b/src/stage1.zig @@ -39,12 +39,11 @@ pub export fn main(argc: c_int, argv: [*]const [*:0]const u8) c_int { for (args) |*arg, i| { arg.* = mem.spanZ(argv[i]); } - stage2.mainArgs(gpa, arena, args) catch |err| { - if (@errorReturnTrace()) |trace| { - std.debug.dumpStackTrace(trace.*); - } - fatal("unhandled internal error: {}", .{@errorName(err)}); - }; + if (std.builtin.mode == .Debug) { + stage2.mainArgs(gpa, arena, args) catch unreachable; + } else { + stage2.mainArgs(gpa, arena, args) catch |err| fatal("{}", .{@errorName(err)}); + } return 0; } From a2b86777b536a71216628a052faf5a184e63fd33 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 3 Oct 2020 17:21:45 -0700 Subject: [PATCH 46/55] fix alignment in CLI usage text --- src/main.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.zig b/src/main.zig index d1017a911d..32ce3995c5 100644 --- a/src/main.zig +++ b/src/main.zig @@ -273,7 +273,7 @@ const usage_build_generic = \\ -rdynamic Add all symbols to the dynamic symbol table \\ -rpath [path] Add directory to the runtime library search path \\ --eh-frame-hdr Enable C++ exception handling by passing --eh-frame-hdr to linker - \\ --emit-relocs Enable output of relocation sections for post build tools + \\ --emit-relocs Enable output of relocation sections for post build tools \\ -dynamic Force output to be dynamically linked \\ -static Force output to be statically linked \\ -Bsymbolic Bind global references locally From b306149b22aa7bdf9b02cce788406452926a88c4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 3 Oct 2020 17:27:09 -0700 Subject: [PATCH 47/55] `zig run foo.c` is perfectly valid --- src/main.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.zig b/src/main.zig index 32ce3995c5..0868839257 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1210,8 +1210,8 @@ fn buildOutputType( fatal("translate-c expects exactly 1 source file (found {})", .{c_source_files.items.len}); } - if (root_src_file == null and (arg_mode == .zig_test or arg_mode == .run)) { - fatal("one zig source file is required to run this command", .{}); + if (root_src_file == null and arg_mode == .zig_test) { + fatal("one zig source file is required to run `zig test`", .{}); } const root_name = if (provided_name) |n| n else blk: { From d1e779cea82665a05a9e6e3427e8ea117f7a9eaf Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 3 Oct 2020 17:33:51 -0700 Subject: [PATCH 48/55] ci: update azure msys base installer hopefully resolves the CI failures --- ci/azure/pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/azure/pipelines.yml b/ci/azure/pipelines.yml index 7cd1d596b4..0c42fdb221 100644 --- a/ci/azure/pipelines.yml +++ b/ci/azure/pipelines.yml @@ -41,7 +41,7 @@ jobs: steps: - powershell: | - (New-Object Net.WebClient).DownloadFile("https://github.com/msys2/msys2-installer/releases/download/2020-07-20/msys2-base-x86_64-20200720.sfx.exe", "sfx.exe") + (New-Object Net.WebClient).DownloadFile("https://github.com/msys2/msys2-installer/releases/download/2020-09-03/msys2-base-x86_64-20200903.sfx.exe", "sfx.exe") .\sfx.exe -y -o\ del sfx.exe displayName: Download/Extract/Install MSYS2 From 26546af1b892925e1cfeb06564c7296e85abc840 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Sat, 3 Oct 2020 15:26:07 -0600 Subject: [PATCH 49/55] Revert "Include dbg.h to third-party libs" This reverts commit c8b4cc2ff9cf15a42f95b2302e02431a0004f5c8. This includes many C++ standard library headers: #include #include #include #include #include #include #include #include #include #include #include #include which adds more than a second of compile time for each file that includes the header: ir.cpp before: 8.041s ir.cpp after: 6.847s --- CMakeLists.txt | 1 - deps/dbg-macro/LICENSE | 21 -- deps/dbg-macro/README.md | 172 ---------- deps/dbg-macro/dbg.h | 711 --------------------------------------- src/stage1/all_types.hpp | 5 - 5 files changed, 910 deletions(-) delete mode 100644 deps/dbg-macro/LICENSE delete mode 100644 deps/dbg-macro/README.md delete mode 100644 deps/dbg-macro/dbg.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e342e42e2..63ac2b999e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -257,7 +257,6 @@ target_include_directories(embedded_softfloat PUBLIC ) include_directories("${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/include") set(SOFTFLOAT_LIBRARIES embedded_softfloat) -include_directories("${CMAKE_SOURCE_DIR}/deps/dbg-macro") find_package(Threads) diff --git a/deps/dbg-macro/LICENSE b/deps/dbg-macro/LICENSE deleted file mode 100644 index 243854e613..0000000000 --- a/deps/dbg-macro/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2019 David Peter - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/deps/dbg-macro/README.md b/deps/dbg-macro/README.md deleted file mode 100644 index a142d31432..0000000000 --- a/deps/dbg-macro/README.md +++ /dev/null @@ -1,172 +0,0 @@ -# `dbg(…)` - -[![Build Status](https://travis-ci.org/sharkdp/dbg-macro.svg?branch=master)](https://travis-ci.org/sharkdp/dbg-macro) [![Build status](https://ci.appveyor.com/api/projects/status/vmo9rw4te2wifkul/branch/master?svg=true)](https://ci.appveyor.com/project/sharkdp/dbg-macro) [![Try it online](https://img.shields.io/badge/try-online-f34b7d.svg)](https://repl.it/@sharkdp/dbg-macro-demo) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](dbg.h) - -*A macro for `printf`-style debugging fans.* - -Debuggers are great. But sometimes you just don't have the time or patience to set -up everything correctly and just want a quick way to inspect some values at runtime. - -This projects provides a [single header file](dbg.h) with a `dbg(…)` -macro that can be used in all circumstances where you would typically write -`printf("…", …)` or `std::cout << …`. But it comes with a few extras. - -## Examples - -``` c++ -#include -#include - -// You can use "dbg(..)" in expressions: -int factorial(int n) { - if (dbg(n <= 1)) { - return dbg(1); - } else { - return dbg(n * factorial(n - 1)); - } -} - -int main() { - std::string message = "hello"; - dbg(message); // [example.cpp:15 (main)] message = "hello" (std::string) - - const int a = 2; - const int b = dbg(3 * a) + 1; // [example.cpp:18 (main)] 3 * a = 6 (int) - - std::vector numbers{b, 13, 42}; - dbg(numbers); // [example.cpp:21 (main)] numbers = {7, 13, 42} (size: 3) (std::vector) - - dbg("this line is executed"); // [example.cpp:23 (main)] this line is executed - - factorial(4); - - return 0; -} -``` - -The code above produces this output ([try it yourself](https://repl.it/@sharkdp/dbg-macro-demo)): - -![dbg(…) macro output](https://i.imgur.com/NHEYk9A.png) - -## Features - - * Easy to read, colorized output (colors auto-disable when the output is not an interactive terminal) - * Prints file name, line number, function name and the original expression - * Adds type information for the printed-out value - * Specialized pretty-printers for containers, pointers, string literals, enums, `std::optional`, etc. - * Can be used inside expressions (passing through the original value) - * The `dbg.h` header issues a compiler warning when included (so you don't forget to remove it). - * Compatible and tested with C++11, C++14 and C++17. - -## Installation - -To make this practical, the `dbg.h` header should to be readily available from all kinds of different -places and in all kinds of environments. The quick & dirty way is to actually copy the header file -to `/usr/include` or to clone the repository and symlink `dbg.h` to `/usr/include/dbg.h`. -``` bash -git clone https://github.com/sharkdp/dbg-macro -sudo ln -s $(readlink -f dbg-macro/dbg.h) /usr/include/dbg.h -``` -If you don't want to make untracked changes to your filesystem, check below if there is a package for -your operating system or package manager. - -### On Arch Linux - -You can install [`dbg-macro` from the AUR](https://aur.archlinux.org/packages/dbg-macro/): -``` bash -yay -S dbg-macro -``` - -### With vcpkg - -You can install the [`dbg-macro` port](https://github.com/microsoft/vcpkg/tree/master/ports/dbg-macro) via: -``` bash -vcpkg install dbg-macro -``` - -## Configuration - -* Set the `DBG_MACRO_DISABLE` flag to disable the `dbg(…)` macro (i.e. to make it a no-op). -* Set the `DBG_MACRO_NO_WARNING` flag to disable the *"'dbg.h' header is included in your code base"* warnings. - -## Advanced features - -### Hexadecimal, octal and binary format - -If you want to format integers in hexadecimal, octal or binary representation, you can -simply wrap them in `dbg::hex(…)`, `dbg::oct(…)` or `dbg::bin(…)`: -```c++ -const uint32_t secret = 12648430; -dbg(dbg::hex(secret)); -``` - -### Printing type names - -`dbg(…)` already prints the type for each value in parenthesis (see screenshot above). But -sometimes you just want to print a type (maybe because you don't have a value for that type). -In this case, you can use the `dbg::type()` helper to pretty-print a given type `T`. -For example: -```c++ -template -void my_function_template() { - using MyDependentType = typename std::remove_reference::type&&; - dbg(dbg::type()); -} -``` - -### Print the current time - -To print a timestamp, you can use the `dbg::time()` helper: -```c++ -dbg(dbg::time()); -``` - -### Customization - -If you want `dbg(…)` to work for your custom datatype, you can simply overload `operator<<` for -`std::ostream&`: -```c++ -std::ostream& operator<<(std::ostream& out, const user_defined_type& v) { - out << "…"; - return out; -} -``` - -If you want to modify the type name that is printed by `dbg(…)`, you can add a custom -`get_type_name` overload: -```c++ -// Customization point for type information -namespace dbg { - std::string get_type_name(type_tag) { - return "truth value"; - } -} -``` - -## Development - -If you want to contribute to `dbg-macro`, here is how you can build the tests and demos: - -Make sure that the submodule(s) are up to date: -```bash -git submodule update --init -``` - -Then, use the typical `cmake` workflow. Usage of `-DCMAKE_CXX_STANDARD=17` is optional, -but recommended in order to have the largest set of features enabled: -```bash -mkdir build -cd build -cmake .. -DCMAKE_CXX_STANDARD=17 -make -``` - -To run the tests, simply call: -```bash -make test -``` -You can find the unit tests in `tests/basic.cpp`. - -## Acknowledgement - -This project is inspired by Rusts [`dbg!(…)` macro](https://doc.rust-lang.org/std/macro.dbg.html). diff --git a/deps/dbg-macro/dbg.h b/deps/dbg-macro/dbg.h deleted file mode 100644 index 3a76130514..0000000000 --- a/deps/dbg-macro/dbg.h +++ /dev/null @@ -1,711 +0,0 @@ -/***************************************************************************** - - dbg(...) macro - -License (MIT): - - Copyright (c) 2019 David Peter - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to - deal in the Software without restriction, including without limitation the - rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - sell copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - -*****************************************************************************/ - -#ifndef DBG_MACRO_DBG_H -#define DBG_MACRO_DBG_H - -#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) -#define DBG_MACRO_UNIX -#elif defined(_MSC_VER) -#define DBG_MACRO_WINDOWS -#endif - -#ifndef DBG_MACRO_NO_WARNING -#pragma message("WARNING: the 'dbg.h' header is included in your code base") -#endif // DBG_MACRO_NO_WARNING - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef DBG_MACRO_UNIX -#include -#endif - -#if __cplusplus >= 201703L || defined(_MSC_VER) -#define DBG_MACRO_CXX_STANDARD 17 -#elif __cplusplus >= 201402L -#define DBG_MACRO_CXX_STANDARD 14 -#else -#define DBG_MACRO_CXX_STANDARD 11 -#endif - -#if DBG_MACRO_CXX_STANDARD >= 17 -#include -#include -#endif - -namespace dbg { - -#ifdef DBG_MACRO_UNIX -inline bool isColorizedOutputEnabled() { - return isatty(fileno(stderr)); -} -#else -inline bool isColorizedOutputEnabled() { - return true; -} -#endif - -struct time {}; - -namespace pretty_function { - -// Compiler-agnostic version of __PRETTY_FUNCTION__ and constants to -// extract the template argument in `type_name_impl` - -#if defined(__clang__) -#define DBG_MACRO_PRETTY_FUNCTION __PRETTY_FUNCTION__ -static constexpr size_t PREFIX_LENGTH = - sizeof("const char *dbg::type_name_impl() [T = ") - 1; -static constexpr size_t SUFFIX_LENGTH = sizeof("]") - 1; -#elif defined(__GNUC__) && !defined(__clang__) -#define DBG_MACRO_PRETTY_FUNCTION __PRETTY_FUNCTION__ -static constexpr size_t PREFIX_LENGTH = - sizeof("const char* dbg::type_name_impl() [with T = ") - 1; -static constexpr size_t SUFFIX_LENGTH = sizeof("]") - 1; -#elif defined(_MSC_VER) -#define DBG_MACRO_PRETTY_FUNCTION __FUNCSIG__ -static constexpr size_t PREFIX_LENGTH = - sizeof("const char *__cdecl dbg::type_name_impl<") - 1; -static constexpr size_t SUFFIX_LENGTH = sizeof(">(void)") - 1; -#else -#error "This compiler is currently not supported by dbg_macro." -#endif - -} // namespace pretty_function - -// Formatting helpers - -template -struct print_formatted { - static_assert(std::is_integral::value, - "Only integral types are supported."); - - print_formatted(T value, int numeric_base) - : inner(value), base(numeric_base) {} - - operator T() const { return inner; } - - const char* prefix() const { - switch (base) { - case 8: - return "0o"; - case 16: - return "0x"; - case 2: - return "0b"; - default: - return ""; - } - } - - T inner; - int base; -}; - -template -print_formatted hex(T value) { - return print_formatted{value, 16}; -} - -template -print_formatted oct(T value) { - return print_formatted{value, 8}; -} - -template -print_formatted bin(T value) { - return print_formatted{value, 2}; -} - -// Implementation of 'type_name()' - -template -const char* type_name_impl() { - return DBG_MACRO_PRETTY_FUNCTION; -} - -template -struct type_tag {}; - -template -std::string get_type_name(type_tag) { - namespace pf = pretty_function; - - std::string type = type_name_impl(); - return type.substr(pf::PREFIX_LENGTH, - type.size() - pf::PREFIX_LENGTH - pf::SUFFIX_LENGTH); -} - -template -std::string type_name() { - if (std::is_volatile::value) { - if (std::is_pointer::value) { - return type_name::type>() + " volatile"; - } else { - return "volatile " + type_name::type>(); - } - } - if (std::is_const::value) { - if (std::is_pointer::value) { - return type_name::type>() + " const"; - } else { - return "const " + type_name::type>(); - } - } - if (std::is_pointer::value) { - return type_name::type>() + "*"; - } - if (std::is_lvalue_reference::value) { - return type_name::type>() + "&"; - } - if (std::is_rvalue_reference::value) { - return type_name::type>() + "&&"; - } - return get_type_name(type_tag{}); -} - -inline std::string get_type_name(type_tag) { - return "short"; -} - -inline std::string get_type_name(type_tag) { - return "unsigned short"; -} - -inline std::string get_type_name(type_tag) { - return "long"; -} - -inline std::string get_type_name(type_tag) { - return "unsigned long"; -} - -inline std::string get_type_name(type_tag) { - return "std::string"; -} - -template -std::string get_type_name(type_tag>>) { - return "std::vector<" + type_name() + ">"; -} - -template -std::string get_type_name(type_tag>) { - return "std::pair<" + type_name() + ", " + type_name() + ">"; -} - -template -std::string type_list_to_string() { - std::string result; - auto unused = {(result += type_name() + ", ", 0)..., 0}; - static_cast(unused); - - if (sizeof...(T) > 0) { - result.pop_back(); - result.pop_back(); - } - return result; -} - -template -std::string get_type_name(type_tag>) { - return "std::tuple<" + type_list_to_string() + ">"; -} - -template -inline std::string get_type_name(type_tag>) { - return type_name(); -} - -// Implementation of 'is_detected' to specialize for container-like types - -namespace detail_detector { - -struct nonesuch { - nonesuch() = delete; - ~nonesuch() = delete; - nonesuch(nonesuch const&) = delete; - void operator=(nonesuch const&) = delete; -}; - -template -using void_t = void; - -template - class Op, - class... Args> -struct detector { - using value_t = std::false_type; - using type = Default; -}; - -template class Op, class... Args> -struct detector>, Op, Args...> { - using value_t = std::true_type; - using type = Op; -}; - -} // namespace detail_detector - -template