From 1483ae37f2dae6a5b9db1f7851cf5dc9a86e57f3 Mon Sep 17 00:00:00 2001 From: Bas Date: Wed, 19 Feb 2020 17:33:35 +0100 Subject: [PATCH 1/7] Add an appendValues method to ArrayList to append a value n times. (#4460) --- lib/std/array_list.zig | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/lib/std/array_list.zig b/lib/std/array_list.zig index f212ae8659..d1946be02a 100644 --- a/lib/std/array_list.zig +++ b/lib/std/array_list.zig @@ -188,6 +188,14 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { self.len += items.len; } + /// Append a value to the list `n` times. Allocates more memory + /// as necessary. + pub fn appendNTimes(self: *Self, value: T, n: usize) !void { + const old_len = self.len; + try self.resize(self.len + n); + mem.set(T, self.items[old_len..self.len], value); + } + /// Adjust the list's length to `new_len`. Doesn't initialize /// added items if any. pub fn resize(self: *Self, new_len: usize) !void { @@ -311,6 +319,23 @@ test "std.ArrayList.basic" { 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.len); + for (list.toSlice()) |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.orderedRemove" { var list = ArrayList(i32).init(testing.allocator); defer list.deinit(); From 81cc52d4af1f1ecd05d8b75c3cfdc0105a3c53c3 Mon Sep 17 00:00:00 2001 From: Michael Dusan Date: Thu, 20 Feb 2020 00:38:35 -0500 Subject: [PATCH 2/7] stage1/ir_print: show GenConst in trailing fahsion --- src/ir_print.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 47c984f2ef..c0a127dd16 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -590,11 +590,6 @@ static void ir_print_const_value(CodeGen *g, FILE *f, ZigValue *const_val) { static void ir_print_other_inst_gen(IrPrintGen *irp, IrInstGen *inst) { if (inst == nullptr) { fprintf(irp->f, "(null)"); - return; - } - - if (inst->value->special != ConstValSpecialRuntime) { - ir_print_const_value(irp->codegen, irp->f, inst->value); } else { ir_print_var_gen(irp, inst); } From a3855477866bbe59b0583ca07170a981e7ca5839 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Thu, 20 Feb 2020 13:14:19 +0100 Subject: [PATCH 3/7] ir: Compile error on result_loc type mismatch w/ slicing Closes #4508 --- src/ir.cpp | 14 ++++++++++++-- test/compile_errors.zig | 12 ++++++++++++ test/tests.zig | 6 ++++-- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 3044d54d17..5f50586f72 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -26677,9 +26677,19 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i IrInstGen *result_loc = ir_resolve_result(ira, &instruction->base.base, instruction->result_loc, return_type, nullptr, true, true); - if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) { - return result_loc; + + if (result_loc != nullptr) { + if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) { + return result_loc; + } + IrInstGen *dummy_value = ir_const(ira, &instruction->base.base, return_type); + dummy_value->value->special = ConstValSpecialRuntime; + IrInstGen *dummy_result = ir_implicit_cast2(ira, &instruction->base.base, + dummy_value, result_loc->value->type->data.pointer.child_type); + if (type_is_invalid(dummy_result->value->type)) + return ira->codegen->invalid_inst_gen; } + return ir_build_slice_gen(ira, &instruction->base.base, return_type, ptr_ptr, casted_start, end, instruction->safety_check_on, result_loc); } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 9f2b3716b0..1b32786e40 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -3,6 +3,18 @@ const builtin = @import("builtin"); const Target = @import("std").Target; pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest("slice to pointer conversion mismatch", + \\pub fn bytesAsSlice(bytes: var) [*]align(1) const u16 { + \\ return @ptrCast([*]align(1) const u16, bytes.ptr)[0..1]; + \\} + \\test "bytesAsSlice" { + \\ const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF }; + \\ const slice = bytesAsSlice(bytes[0..]); + \\} + , &[_][]const u8{ + "tmp.zig:2:54: error: expected type '[*]align(1) const u16', found '[]align(1) const u16'", + }); + cases.addTest("access invalid @typeInfo decl", \\const A = B; \\test "Crash" { diff --git a/test/tests.zig b/test/tests.zig index f079b4664c..64a46abbc2 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -677,8 +677,10 @@ pub const StackTracesContext = struct { const got: []const u8 = got_result: { var buf = try Buffer.initSize(b.allocator, 0); defer buf.deinit(); - var bytes = stderr.toSliceConst(); - if (bytes.len != 0 and bytes[bytes.len - 1] == '\n') bytes = bytes[0 .. bytes.len - 1]; + const bytes = if (stderr.endsWith("\n")) + stderr.toSliceConst()[0 .. stderr.len() - 1] + else + stderr.toSliceConst()[0..stderr.len()]; var it = mem.separate(bytes, "\n"); process_lines: while (it.next()) |line| { if (line.len == 0) continue; From ae16a6773fd7853a3589b5650a33b4b8d37b9ef8 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Thu, 20 Feb 2020 13:25:45 +0100 Subject: [PATCH 4/7] std: Handle NO_MEDIA_IN_DEVICE error in openFileWindows Closes #4507 --- lib/std/fs.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/std/fs.zig b/lib/std/fs.zig index a00ba6a63f..3bb89f5d7e 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -864,6 +864,7 @@ pub const Dir = struct { .OBJECT_NAME_INVALID => unreachable, .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, .OBJECT_PATH_NOT_FOUND => return error.FileNotFound, + .NO_MEDIA_IN_DEVICE => return error.FileNotFound, .INVALID_PARAMETER => unreachable, .SHARING_VIOLATION => return error.SharingViolation, .ACCESS_DENIED => return error.AccessDenied, From ec889d5888c57d0337a1e00398d71241a9716ebe Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 20 Feb 2020 12:39:46 -0500 Subject: [PATCH 5/7] NO_MEDIA_IN_DEVICE => return error.NoDevice --- 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 3bb89f5d7e..c3d418eb8c 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -864,7 +864,7 @@ pub const Dir = struct { .OBJECT_NAME_INVALID => unreachable, .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, .OBJECT_PATH_NOT_FOUND => return error.FileNotFound, - .NO_MEDIA_IN_DEVICE => return error.FileNotFound, + .NO_MEDIA_IN_DEVICE => return error.NoDevice, .INVALID_PARAMETER => unreachable, .SHARING_VIOLATION => return error.SharingViolation, .ACCESS_DENIED => return error.AccessDenied, From b0d2ebe529593566f209d34d5bbbfd72cde2a6b9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 20 Feb 2020 13:43:05 -0500 Subject: [PATCH 6/7] remove std.io.readLine This was deceptive. It was always meant to be sort of a "GNU readline" sort of thing where it provides a Command Line Interface to input text. However that functionality did not exist and it was basically a red herring for people trying to read line-delimited input from a stream. In this commit the API is deleted, so that people can find the proper API more easily. A CLI text input abstraction would be useful but may not even need to be in the standard library. As you can see in this commit, the guess_number CLI game gets by just fine by using `std.fs.File.read`. --- lib/std/io.zig | 67 --------------------------- test/standalone/guess_number/main.zig | 14 +++--- 2 files changed, 7 insertions(+), 74 deletions(-) diff --git a/lib/std/io.zig b/lib/std/io.zig index 22ba0b9bf4..b6e1b12534 100644 --- a/lib/std/io.zig +++ b/lib/std/io.zig @@ -790,73 +790,6 @@ pub const BufferedAtomicFile = struct { } }; -pub fn readLine(buf: *std.Buffer) ![]u8 { - var stdin_stream = getStdIn().inStream(); - return readLineFrom(&stdin_stream.stream, buf); -} - -/// Reads all characters until the next newline into buf, and returns -/// a slice of the characters read (excluding the newline character(s)). -pub fn readLineFrom(stream: var, buf: *std.Buffer) ![]u8 { - const start = buf.len(); - while (true) { - const byte = try stream.readByte(); - switch (byte) { - '\r' => { - // trash the following \n - _ = try stream.readByte(); - return buf.toSlice()[start..]; - }, - '\n' => return buf.toSlice()[start..], - else => try buf.appendByte(byte), - } - } -} - -test "io.readLineFrom" { - var buf = try std.Buffer.initSize(testing.allocator, 0); - defer buf.deinit(); - var mem_stream = SliceInStream.init( - \\Line 1 - \\Line 22 - \\Line 333 - ); - const stream = &mem_stream.stream; - - testing.expectEqualSlices(u8, "Line 1", try readLineFrom(stream, &buf)); - testing.expectEqualSlices(u8, "Line 22", try readLineFrom(stream, &buf)); - testing.expectError(error.EndOfStream, readLineFrom(stream, &buf)); - testing.expectEqualSlices(u8, "Line 1Line 22Line 333", buf.toSlice()); -} - -pub fn readLineSlice(slice: []u8) ![]u8 { - var stdin_stream = getStdIn().inStream(); - return readLineSliceFrom(&stdin_stream.stream, slice); -} - -/// Reads all characters until the next newline into slice, and returns -/// a slice of the characters read (excluding the newline character(s)). -pub fn readLineSliceFrom(stream: var, slice: []u8) ![]u8 { - // We cannot use Buffer.fromOwnedSlice, as it wants to append a null byte - // after taking ownership, which would always require an allocation. - var buf = std.Buffer{ .list = std.ArrayList(u8).fromOwnedSlice(testing.failing_allocator, slice) }; - try buf.resize(0); - return try readLineFrom(stream, &buf); -} - -test "io.readLineSliceFrom" { - var buf: [7]u8 = undefined; - var mem_stream = SliceInStream.init( - \\Line 1 - \\Line 22 - \\Line 333 - ); - const stream = &mem_stream.stream; - - testing.expectEqualSlices(u8, "Line 1", try readLineSliceFrom(stream, buf[0..])); - testing.expectError(error.OutOfMemory, readLineSliceFrom(stream, buf[0..])); -} - pub const Packing = enum { /// Pack data to byte alignment Byte, diff --git a/test/standalone/guess_number/main.zig b/test/standalone/guess_number/main.zig index ce7d58ac17..f5b3b36993 100644 --- a/test/standalone/guess_number/main.zig +++ b/test/standalone/guess_number/main.zig @@ -5,6 +5,7 @@ const fmt = std.fmt; pub fn main() !void { const stdout = &io.getStdOut().outStream().stream; + const stdin = io.getStdIn(); try stdout.print("Welcome to the Guess Number Game in Zig.\n", .{}); @@ -22,13 +23,12 @@ pub fn main() !void { try stdout.print("\nGuess a number between 1 and 100: ", .{}); var line_buf: [20]u8 = undefined; - const line = io.readLineSlice(line_buf[0..]) catch |err| switch (err) { - error.OutOfMemory => { - try stdout.print("Input too long.\n", .{}); - continue; - }, - else => return err, - }; + const amt = try stdin.read(&line_buf); + if (amt == line_buf.len) { + try stdout.print("Input too long.\n", .{}); + continue; + } + const line = std.mem.trimRight(u8, line_buf[0..amt], "\r\n"); const guess = fmt.parseUnsigned(u8, line, 10) catch { try stdout.print("Invalid number.\n", .{}); From e381a42de9c0f0c5439a926b0ac99026a0373f49 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 20 Feb 2020 17:02:29 -0500 Subject: [PATCH 7/7] quick fix: add -mcpu=baseline support to zig0 When the build.zig logic to build libzigstage2 was converted to a cmake command, it neglected to use baseline CPU features rather than compiling with native features. This adds a hard coded flag `-mcpu=baseline` which can be used to detect the native target, but mark it as non-native so that it does not get the CPU features specific to the host used to compile libzigstage2. Full `-mcpu` support is happening in the upcoming pull request #4509, and so this "quick fix" will be cleaned up in that branch, before it is merged to master. closes #4506 --- CMakeLists.txt | 1 + src/main.cpp | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index ab4607d230..a3d6a7fb68 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -616,6 +616,7 @@ endif() set(BUILD_LIBSTAGE2_ARGS "build-lib" "src-self-hosted/stage2.zig" + -mcpu=baseline --name zigstage2 --override-lib-dir "${CMAKE_SOURCE_DIR}/lib" --cache on diff --git a/src/main.cpp b/src/main.cpp index d7f5e5b7b0..5046c92ddd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -450,6 +450,7 @@ static int main0(int argc, char **argv) { const char *cpu = nullptr; const char *features = nullptr; CodeModel code_model = CodeModelDefault; + bool baseline_cpu = false; ZigList llvm_argv = {0}; llvm_argv.append("zig (LLVM option parsing)"); @@ -716,6 +717,8 @@ static int main0(int argc, char **argv) { emit_llvm_ir = true; } else if (strcmp(arg, "-fno-emit-llvm-ir") == 0) { emit_llvm_ir = false; + } else if (strcmp(arg, "-mcpu=baseline") == 0) { + baseline_cpu = true; } else if (i + 1 >= argc) { fprintf(stderr, "Expected another argument after %s\n", arg); return print_error_usage(arg0); @@ -977,6 +980,9 @@ static int main0(int argc, char **argv) { fprintf(stderr, "-target-glibc provided but no -target parameter\n"); return print_error_usage(arg0); } + if (baseline_cpu) { + target.is_native = false; + } } else { if ((err = target_parse_triple(&target, target_string))) { if (err == ErrorUnknownArchitecture && target.arch != ZigLLVM_UnknownArch) {