From 0de35af98b3404f0cf7cd9497f661239d197bbbf Mon Sep 17 00:00:00 2001 From: antlilja Date: Mon, 22 Jun 2020 12:14:52 +0200 Subject: [PATCH 1/8] Add duplicate checking for switch on types * Add compile error tests --- src/ir.cpp | 32 +++++++++++++++++++++++++++++++- test/compile_errors.zig | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/ir.cpp b/src/ir.cpp index 3fa138ed8e..01c7936f75 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -28861,7 +28861,37 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, ir_add_error(ira, &instruction->base.base, buf_sprintf("else prong required when switching on type '%s'", buf_ptr(&switch_type->name))); return ira->codegen->invalid_inst_gen; - } + } else if(switch_type->id == ZigTypeIdMetaType) { + HashMap prevs; + // HashMap doubles capacity when reaching 60% capacity, + // because we know the size at init we can avoid reallocation by doubling it here + prevs.init(instruction->range_count * 2); + for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { + IrInstSrcCheckSwitchProngsRange *range = &instruction->ranges[range_i]; + + IrInstGen *value = range->start->child; + IrInstGen *casted_value = ir_implicit_cast(ira, value, switch_type); + if (type_is_invalid(casted_value->value->type)) { + prevs.deinit(); + return ira->codegen->invalid_inst_gen; + } + + ZigValue *const_expr_val = ir_resolve_const(ira, casted_value, UndefBad); + if (!const_expr_val) { + prevs.deinit(); + return ira->codegen->invalid_inst_gen; + } + + auto entry = prevs.put_unique(const_expr_val->data.x_type, value); + if(entry != nullptr) { + ErrorMsg *msg = ir_add_error(ira, &value->base, buf_sprintf("duplicate switch value")); + add_error_note(ira->codegen, msg, entry->value->base.source_node, buf_sprintf("previous value is here")); + prevs.deinit(); + return ira->codegen->invalid_inst_gen; + } + } + prevs.deinit(); + } return ir_const_void(ira, &instruction->base.base); } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index e3dd1f0d8f..e8b7e610ee 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -4362,6 +4362,40 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:5:14: note: previous value is here", }); + cases.add("switch expression - duplicate type", + \\fn foo(comptime T: type, x: T) u8 { + \\ return switch (T) { + \\ u32 => 0, + \\ u64 => 1, + \\ u32 => 2, + \\ else => 3, + \\ }; + \\} + \\export fn entry() usize { return @sizeOf(@TypeOf(foo(u32, 0))); } + , &[_][]const u8{ + "tmp.zig:5:9: error: duplicate switch value", + "tmp.zig:3:9: note: previous value is here", + }); + + cases.add("switch expression - duplicate type (struct alias)", + \\const Test = struct { + \\ bar: i32, + \\}; + \\const Test2 = Test; + \\fn foo(comptime T: type, x: T) u8 { + \\ return switch (T) { + \\ Test => 0, + \\ u64 => 1, + \\ Test2 => 2, + \\ else => 3, + \\ }; + \\} + \\export fn entry() usize { return @sizeOf(@TypeOf(foo(u32, 0))); } + , &[_][]const u8{ + "tmp.zig:9:9: error: duplicate switch value", + "tmp.zig:7:9: note: previous value is here", + }); + cases.add("switch expression - switch on pointer type with no else", \\fn foo(x: *u8) void { \\ switch (x) { From 66e5205047576768f075ec8f016f6fe21ce71bd0 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 23 Jun 2020 21:54:36 +0200 Subject: [PATCH 2/8] Refactor PreopenList.find() This commit generalizes `std.fs.wasi.PreopenList.find(...)` allowing search by `std.fs.wasi.PreopenType` union type rather than by dir name. In the future releases of WASI, it is expected to have more preopen types (or capabilities) than just directories. This commit aligns itself with that vision. This is a potentially breaking change. However, since `std.fs.wasi.PreopenList` wasn't made part of any Zig release yet, I think we should be OK to introduce those changes without pointing to any deprecations. --- doc/langref.html.in | 2 +- lib/std/fs/wasi.zig | 77 ++++++++++++++++++++++++--------------------- lib/std/testing.zig | 2 +- 3 files changed, 44 insertions(+), 37 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index aaa15e91d0..8974e6d175 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -9738,7 +9738,7 @@ pub fn main() !void { } {#code_end#}
$ wasmtime --dir=. preopens.wasm
-0: { .fd = 3, .Dir = '.' }
+0: Preopen{ .fd = 3, .type = PreopenType{ .Dir = '.' } }
 
{#header_close#} {#header_close#} diff --git a/lib/std/fs/wasi.zig b/lib/std/fs/wasi.zig index f08c74c129..fb6e6679fd 100644 --- a/lib/std/fs/wasi.zig +++ b/lib/std/fs/wasi.zig @@ -5,11 +5,37 @@ const Allocator = mem.Allocator; usingnamespace std.os.wasi; +/// Type-tag of WASI preopen. +/// +/// WASI currently offers only `Dir` as a valid preopen resource. +pub const PreopenTypeTag = enum { + Dir, +}; + /// Type of WASI preopen. /// /// WASI currently offers only `Dir` as a valid preopen resource. -pub const PreopenType = enum { - Dir, +pub const PreopenType = union(PreopenTypeTag) { + /// Preopened directory type. + Dir: []const u8, + + const Self = @This(); + + pub fn eql(self: Self, other: PreopenType) bool { + if (!mem.eql(u8, @tagName(self), @tagName(other))) return false; + + switch (self) { + PreopenTypeTag.Dir => |this_path| return mem.eql(u8, this_path, other.Dir), + } + } + + pub fn format(self: Self, comptime fmt: []const u8, options: std.fmt.FormatOptions, out_stream: var) !void { + try out_stream.print("PreopenType{{ ", .{}); + switch (self) { + PreopenType.Dir => |path| try out_stream.print(".Dir = '{}'", .{path}), + } + return out_stream.print(" }}", .{}); + } }; /// WASI preopen struct. This struct consists of a WASI file descriptor @@ -20,29 +46,15 @@ pub const Preopen = struct { fd: fd_t, /// Type of the preopen. - @"type": union(PreopenType) { - /// Path to a preopened directory. - Dir: []const u8, - }, + @"type": PreopenType, - const Self = @This(); - - /// Construct new `Preopen` instance of type `PreopenType.Dir` from - /// WASI file descriptor and WASI path. - pub fn newDir(fd: fd_t, path: []const u8) Self { - return Self{ + /// Construct new `Preopen` instance. + pub fn new(fd: fd_t, preopen_type: PreopenType) Preopen { + return Preopen{ .fd = fd, - .@"type" = .{ .Dir = path }, + .@"type" = preopen_type, }; } - - pub fn format(self: Self, comptime fmt: []const u8, options: std.fmt.FormatOptions, out_stream: var) !void { - try out_stream.print("{{ .fd = {}, ", .{self.fd}); - switch (self.@"type") { - PreopenType.Dir => |path| try out_stream.print(".Dir = '{}'", .{path}), - } - return out_stream.print(" }}", .{}); - } }; /// Dynamically-sized array list of WASI preopens. This struct is a @@ -113,24 +125,18 @@ pub const PreopenList = struct { ESUCCESS => {}, else => |err| return os.unexpectedErrno(err), } - const preopen = Preopen.newDir(fd, path_buf); + const preopen = Preopen.new(fd, PreopenType{ .Dir = path_buf }); try self.buffer.append(preopen); fd += 1; } } - /// Find preopen by path. If the preopen exists, return it. + /// Find preopen by type. If the preopen exists, return it. /// Otherwise, return `null`. - /// - /// TODO make the function more generic by searching by `PreopenType` union. This will - /// be needed in the future when WASI extends its capabilities to resources - /// other than preopened directories. - pub fn find(self: Self, path: []const u8) ?*const Preopen { - for (self.buffer.items) |preopen| { - switch (preopen.@"type") { - PreopenType.Dir => |preopen_path| { - if (mem.eql(u8, path, preopen_path)) return &preopen; - }, + pub fn find(self: Self, preopen_type: PreopenType) ?*const Preopen { + for (self.buffer.items) |*preopen| { + if (preopen.@"type".eql(preopen_type)) { + return preopen; } } return null; @@ -156,7 +162,8 @@ test "extracting WASI preopens" { try preopens.populate(); std.testing.expectEqual(@as(usize, 1), preopens.asSlice().len); - const preopen = preopens.find(".") orelse unreachable; - std.testing.expect(std.mem.eql(u8, ".", preopen.@"type".Dir)); + const preopen = preopens.find(PreopenType{ .Dir = "." }) orelse unreachable; + std.debug.print("\n{}\n", .{preopen}); + std.testing.expect(!preopen.@"type".eql(PreopenType{ .Dir = "." })); std.testing.expectEqual(@as(usize, 3), preopen.fd); } diff --git a/lib/std/testing.zig b/lib/std/testing.zig index 2d136d56c9..117a788e16 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -215,7 +215,7 @@ fn getCwdOrWasiPreopen() std.fs.Dir { defer preopens.deinit(); preopens.populate() catch @panic("unable to make tmp dir for testing: unable to populate preopens"); - const preopen = preopens.find(".") orelse + const preopen = preopens.find(std.fs.wasi.PreopenType{ .Dir = "." }) orelse @panic("unable to make tmp dir for testing: didn't find '.' in the preopens"); return std.fs.Dir{ .fd = preopen.fd }; From 5fed725e0a4e8d2617f2b8fc98191103d1ebd3ea Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 23 Jun 2020 23:59:32 +0200 Subject: [PATCH 3/8] Remove some leftover debugging checks --- lib/std/fs/wasi.zig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/std/fs/wasi.zig b/lib/std/fs/wasi.zig index fb6e6679fd..db4317064d 100644 --- a/lib/std/fs/wasi.zig +++ b/lib/std/fs/wasi.zig @@ -163,7 +163,6 @@ test "extracting WASI preopens" { std.testing.expectEqual(@as(usize, 1), preopens.asSlice().len); const preopen = preopens.find(PreopenType{ .Dir = "." }) orelse unreachable; - std.debug.print("\n{}\n", .{preopen}); - std.testing.expect(!preopen.@"type".eql(PreopenType{ .Dir = "." })); + std.testing.expect(preopen.@"type".eql(PreopenType{ .Dir = "." })); std.testing.expectEqual(@as(usize, 3), preopen.fd); } From 93f0bcb649087b5db5cfcba5de5faaaf59047751 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 24 Jun 2020 01:59:19 -0400 Subject: [PATCH 4/8] building mingw-w64 for windows ARM looks in lib64/lib32 for .def files --- src/link.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/link.cpp b/src/link.cpp index 0f27cee9ab..df33a5494e 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -2377,6 +2377,17 @@ static Error find_mingw_lib_def(LinkJob *lj, const char *name, Buf *out_path) { return err; } + if (!does_exist && target_is_arm(g->zig_target)) { + // Try lib32 or lib64 + const bool is_32 = target_arch_pointer_bit_width(g->zig_target->arch) == 32; + lib_path = is_32 ? "lib32" : "lib64"; + buf_resize(&override_path, 0); + buf_appendf(&override_path, "%s" OS_SEP "libc" OS_SEP "mingw" OS_SEP "%s" OS_SEP "%s.def", buf_ptr(g->zig_lib_dir), lib_path, name); + if ((err = os_file_exists(&override_path, &does_exist)) != ErrorNone) { + return err; + } + } + if (!does_exist) { // Try the generic version buf_resize(&override_path, 0); From 3aab6012c471522e2d1cd5a456f56cb9a7addeb6 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 24 Jun 2020 02:08:08 -0400 Subject: [PATCH 5/8] Revert "building mingw-w64 for windows ARM looks in lib64/lib32 for .def files" This reverts commit 93f0bcb649087b5db5cfcba5de5faaaf59047751. This is not correct (from #mingw-w64 IRC): is there no .def file for ntdll on arm 64 bit? or does mingw-w64-crt/lib64/ntdll.def apply to both x86_64 and aarch64? andrewrk: there's none at the moment (as apps rarely link directly against ntdll, and I didn't want to guess needlessly around that one originally when I added arm64 support, before I actually had a real arm64 windows device) andrewrk: but I guess I could/should complete that now (if you need one right now, the libarm32 one probably is the closest match) --- src/link.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/link.cpp b/src/link.cpp index df33a5494e..0f27cee9ab 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -2377,17 +2377,6 @@ static Error find_mingw_lib_def(LinkJob *lj, const char *name, Buf *out_path) { return err; } - if (!does_exist && target_is_arm(g->zig_target)) { - // Try lib32 or lib64 - const bool is_32 = target_arch_pointer_bit_width(g->zig_target->arch) == 32; - lib_path = is_32 ? "lib32" : "lib64"; - buf_resize(&override_path, 0); - buf_appendf(&override_path, "%s" OS_SEP "libc" OS_SEP "mingw" OS_SEP "%s" OS_SEP "%s.def", buf_ptr(g->zig_lib_dir), lib_path, name); - if ((err = os_file_exists(&override_path, &does_exist)) != ErrorNone) { - return err; - } - } - if (!does_exist) { // Try the generic version buf_resize(&override_path, 0); From 3a2cc5decf5674b2d85c15b7d051c2f3bcf30904 Mon Sep 17 00:00:00 2001 From: Jonathan Marler Date: Tue, 23 Jun 2020 23:56:27 -0600 Subject: [PATCH 6/8] azure-pipelines: fix msys2 install --- ci/azure/pipelines.yml | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/ci/azure/pipelines.yml b/ci/azure/pipelines.yml index fdf9d92d7d..388d6db044 100644 --- a/ci/azure/pipelines.yml +++ b/ci/azure/pipelines.yml @@ -40,12 +40,20 @@ jobs: timeoutInMinutes: 360 steps: + - powershell: | + (New-Object Net.WebClient).DownloadFile("https://github.com/msys2/msys2-installer/releases/download/2020-06-02/msys2-base-x86_64-20200602.sfx.exe", "sfx.exe") + .\sfx.exe -y -o\ + del sfx.exe + displayName: Download/Extract/Install MSYS2 - script: | - git clone https://github.com/msys2/msys2-ci-base.git %CD:~0,2%\msys64 - %CD:~0,2%\msys64\usr\bin\rm -rf %CD:~0,2%\msys64\.git - set PATH=%CD:~0,2%\msys64\usr\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem - %CD:~0,2%\msys64\usr\bin\pacman --noconfirm -Syyuu - displayName: Install and Update MSYS2 + @REM install updated filesystem package first without dependency checking + @REM because of: https://github.com/msys2/MSYS2-packages/issues/2021 + %CD:~0,2%\msys64\usr\bin\bash -lc "pacman --noconfirm -Sydd filesystem" + displayName: Workaround filesystem dash MSYS2 dependency issue + - script: | + %CD:~0,2%\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu" + %CD:~0,2%\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu" + displayName: Update MSYS2 - task: DownloadSecureFile@1 inputs: secureFile: s3cfg From 489c31b6f5ad74bfa0ff1d91c049d0c11f931d94 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 24 Jun 2020 14:36:10 -0400 Subject: [PATCH 7/8] azure ci: install tar and xz with pacman --- ci/azure/windows_msvc_install | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/azure/windows_msvc_install b/ci/azure/windows_msvc_install index ece3bbde11..8ac5181cab 100644 --- a/ci/azure/windows_msvc_install +++ b/ci/azure/windows_msvc_install @@ -4,7 +4,7 @@ set -x set -e pacman -Su --needed --noconfirm -pacman -S --needed --noconfirm wget p7zip python3-pip +pacman -S --needed --noconfirm wget p7zip python3-pip tar xz pip install s3cmd wget -nv "https://ziglang.org/deps/llvm%2bclang%2blld-10.0.0-x86_64-windows-msvc-release-mt.tar.xz" tar xf llvm+clang+lld-10.0.0-x86_64-windows-msvc-release-mt.tar.xz From 129a4fb251f8eab22eacf219fbf81006baec3251 Mon Sep 17 00:00:00 2001 From: Alexandros Naskos Date: Wed, 24 Jun 2020 20:00:11 +0300 Subject: [PATCH 8/8] Copy union const values correctly --- src/analyze.cpp | 6 ++++++ test/stage1/behavior/type_info.zig | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/src/analyze.cpp b/src/analyze.cpp index 542fbb56ce..699b121276 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -9597,6 +9597,12 @@ void copy_const_val(CodeGen *g, ZigValue *dest, ZigValue *src) { break; } } + } else if (dest->type->id == ZigTypeIdUnion) { + bigint_init_bigint(&dest->data.x_union.tag, &src->data.x_union.tag); + dest->data.x_union.payload = g->pass1_arena->create(); + copy_const_val(g, dest->data.x_union.payload, src->data.x_union.payload); + dest->data.x_union.payload->parent.id = ConstParentIdUnion; + dest->data.x_union.payload->parent.data.p_union.union_val = dest; } else if (type_has_optional_repr(dest->type) && dest->data.x_optional != nullptr) { dest->data.x_optional = g->pass1_arena->create(); copy_const_val(g, dest->data.x_optional, src->data.x_optional); diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig index 41301f290d..68ff3aa310 100644 --- a/test/stage1/behavior/type_info.zig +++ b/test/stage1/behavior/type_info.zig @@ -402,3 +402,11 @@ test "type info for async frames" { else => unreachable, } } + +test "type info: value is correctly copied" { + comptime { + var ptrInfo = @typeInfo([]u32); + ptrInfo.Pointer.size = .One; + expect(@typeInfo([]u32).Pointer.size == .Slice); + } +}