From f6d83ba9185dd81106c731e12ab361685fa226c4 Mon Sep 17 00:00:00 2001 From: Vexu <15308111+Vexu@users.noreply.github.com> Date: Tue, 25 Jun 2019 01:12:28 +0300 Subject: [PATCH 01/23] fixed comment formatting in arrays and fn params --- std/zig/parser_test.zig | 38 ++++++++++++++++++++++++++++++++++++++ std/zig/render.zig | 8 ++++---- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/std/zig/parser_test.zig b/std/zig/parser_test.zig index 281f09d57b2771b2357a94392cdc0d7f991a4f67..dc3e6190f5d55cd7e515a0912c3c1fa24be871c7 100644 --- a/std/zig/parser_test.zig +++ b/std/zig/parser_test.zig @@ -2234,6 +2234,44 @@ test "zig fmt: multiline string in array" { ); } +test "zig fmt: line comment in array" { + try testTransform( + \\test "a" { + \\ var arr = [_]u32{ + \\ 0 + \\ // 1, + \\ // 2, + \\ }; + \\} + \\ + , + \\test "a" { + \\ var arr = [_]u32{ + \\ 0, // 1, + \\ // 2, + \\ }; + \\} + \\ + ); +} + +test "zig fmt: comment after params" { + try testTransform( + \\fn a( + \\ b: u32 + \\ // c: u32, + \\ // d: u32, + \\) void {} + \\ + , + \\fn a( + \\ b: u32, // c: u32, + \\ // d: u32, + \\) void {} + \\ + ); +} + const std = @import("std"); const mem = std.mem; const warn = std.debug.warn; diff --git a/std/zig/render.zig b/std/zig/render.zig index ef5c8f2346214473ee07382f288eb5be4cb9c07d..b66cbeb86069ead4359caaccbc8dee168657ea39 100644 --- a/std/zig/render.zig +++ b/std/zig/render.zig @@ -658,7 +658,7 @@ fn renderExpression( try renderToken(tree, stream, lbrace, indent, start_col, Space.None); return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); } - if (exprs.len == 1) { + if (exprs.len == 1 and tree.tokens.at(exprs.at(0).*.lastToken() + 1).id == .RBrace) { const expr = exprs.at(0).*; try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); @@ -719,7 +719,7 @@ fn renderExpression( while (it.next()) |expr| : (i += 1) { counting_stream.bytes_written = 0; var dummy_col: usize = 0; - try renderExpression(allocator, &counting_stream.stream, tree, 0, &dummy_col, expr.*, Space.None); + try renderExpression(allocator, &counting_stream.stream, tree, indent, &dummy_col, expr.*, Space.None); const width = @intCast(usize, counting_stream.bytes_written); const col = i % row_size; column_widths[col] = std.math.max(column_widths[col], width); @@ -1139,8 +1139,8 @@ fn renderExpression( }); const src_params_trailing_comma = blk: { - const maybe_comma = tree.prevToken(rparen); - break :blk tree.tokens.at(maybe_comma).id == Token.Id.Comma; + const maybe_comma = tree.tokens.at(rparen - 1).id; + break :blk maybe_comma == .Comma or maybe_comma == .LineComment; }; if (!src_params_trailing_comma) { -- 2.54.0 From 7325f80bb2aa1759ea5477b8ea26266ecc607db7 Mon Sep 17 00:00:00 2001 From: Vexu <15308111+Vexu@users.noreply.github.com> Date: Wed, 26 Jun 2019 20:03:38 +0300 Subject: [PATCH 02/23] improved comment indentation in arrays --- std/zig/parser_test.zig | 32 ++++++++++++++++++++++++++++++++ std/zig/render.zig | 37 +++++++++++++++++++++++++++++++------ 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/std/zig/parser_test.zig b/std/zig/parser_test.zig index dc3e6190f5d55cd7e515a0912c3c1fa24be871c7..3150c5babd7ecce77c51b0b0851ca43cef43c28b 100644 --- a/std/zig/parser_test.zig +++ b/std/zig/parser_test.zig @@ -2272,6 +2272,38 @@ test "zig fmt: comment after params" { ); } +test "zig fmt: comment in array initializer/access" { + try testCanonical( + \\test "a" { + \\ var a = x{ //aa + \\ //bb + \\ }; + \\ var a = []x{ //aa + \\ //bb + \\ }; + \\ var b = [ //aa + \\ _ + \\ ]x{ //aa + \\ //bb + \\ 9, + \\ }; + \\ var c = b[ //aa + \\ 0 + \\ ]; + \\ var d = [_ + \\ //aa + \\ ]x{ //aa + \\ //bb + \\ 9, + \\ }; + \\ var e = d[0 + \\ //aa + \\ ]; + \\} + \\ + ); +} + const std = @import("std"); const mem = std.mem; const warn = std.debug.warn; diff --git a/std/zig/render.zig b/std/zig/render.zig index b66cbeb86069ead4359caaccbc8dee168657ea39..8270577d7aad39be32a70c4659ffe6aea3434036 100644 --- a/std/zig/render.zig +++ b/std/zig/render.zig @@ -427,9 +427,23 @@ fn renderExpression( }, ast.Node.PrefixOp.Op.ArrayType => |array_index| { - try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.None); // [ - try renderExpression(allocator, stream, tree, indent, start_col, array_index, Space.None); - try renderToken(tree, stream, tree.nextToken(array_index.lastToken()), indent, start_col, Space.None); // ] + const lbracket = prefix_op_node.op_token; + const rbracket = tree.nextToken(array_index.lastToken()); + + try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [ + + const starts_with_comment = tree.tokens.at(lbracket + 1).id == .LineComment; + const ends_with_comment = tree.tokens.at(rbracket - 1).id == .LineComment; + const new_indent = if (ends_with_comment) indent + indent_delta else indent; + const new_space = if (ends_with_comment) Space.Newline else Space.None; + try renderExpression(allocator, stream, tree, new_indent, start_col, array_index, new_space); + if (starts_with_comment) { + try stream.writeByte('\n'); + } + if (ends_with_comment or starts_with_comment) { + try stream.writeByteNTimes(' ', indent); + } + try renderToken(tree, stream, rbracket, indent, start_col, Space.None); // ] }, ast.Node.PrefixOp.Op.BitNot, ast.Node.PrefixOp.Op.BoolNot, @@ -524,7 +538,18 @@ fn renderExpression( try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [ - try renderExpression(allocator, stream, tree, indent, start_col, index_expr, Space.None); + + const starts_with_comment = tree.tokens.at(lbracket + 1).id == .LineComment; + const ends_with_comment = tree.tokens.at(rbracket - 1).id == .LineComment; + const new_indent = if (ends_with_comment) indent + indent_delta else indent; + const new_space = if (ends_with_comment) Space.Newline else Space.None; + try renderExpression(allocator, stream, tree, new_indent, start_col, index_expr, new_space); + if (starts_with_comment) { + try stream.writeByte('\n'); + } + if (ends_with_comment or starts_with_comment) { + try stream.writeByteNTimes(' ', indent); + } return renderToken(tree, stream, rbracket, indent, start_col, space); // ] }, @@ -559,7 +584,7 @@ fn renderExpression( if (field_inits.len == 0) { try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); - try renderToken(tree, stream, lbrace, indent, start_col, Space.None); + try renderToken(tree, stream, lbrace, indent + indent_delta, start_col, Space.None); return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); } @@ -2019,7 +2044,7 @@ fn renderTokenOffset( const after_comment_token = tree.tokens.at(token_index + offset); const next_line_indent = switch (after_comment_token.id) { - Token.Id.RParen, Token.Id.RBrace, Token.Id.RBracket => indent - indent_delta, + Token.Id.RParen, Token.Id.RBrace, Token.Id.RBracket => if (indent > indent_delta) indent - indent_delta else 0, else => indent, }; try stream.writeByteNTimes(' ', next_line_indent); -- 2.54.0 From 0063953d1634ce770ce88519c66e3956832ceb7e Mon Sep 17 00:00:00 2001 From: Vexu <15308111+Vexu@users.noreply.github.com> Date: Thu, 27 Jun 2019 00:30:34 +0300 Subject: [PATCH 03/23] added better test cases --- std/zig/parser_test.zig | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/std/zig/parser_test.zig b/std/zig/parser_test.zig index 876d84e173e9c969fbb0ec06390fcb92744e9772..404c82e9b8f4b65ab95f2a3e1ee3af4ddbce8a11 100644 --- a/std/zig/parser_test.zig +++ b/std/zig/parser_test.zig @@ -2265,6 +2265,16 @@ test "zig fmt: line comment in array" { \\} \\ ); + try testCanonical( + \\test "a" { + \\ var arr = [_]u32{ + \\ 0, + \\ // 1, + \\ // 2, + \\ }; + \\} + \\ + ); } test "zig fmt: comment after params" { @@ -2282,6 +2292,14 @@ test "zig fmt: comment after params" { \\) void {} \\ ); + try testCanonical( + \\fn a( + \\ b: u32, + \\ // c: u32, + \\ // d: u32, + \\) void {} + \\ + ); } test "zig fmt: comment in array initializer/access" { -- 2.54.0 From 1b19c28c79ac20c4b8880742172834f881b47dea Mon Sep 17 00:00:00 2001 From: Jonathan Marler Date: Sat, 24 Aug 2019 01:54:44 -0600 Subject: [PATCH 04/23] Fix issue 3058: zig build segfault --- src/analyze.cpp | 9 +++++++-- test/stage1/behavior/union.zig | 10 ++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 35c598ab97af30f7b7d3ff4a5de0add78390bba3..fa239808f5e23295208b15115ab08e02177280b0 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -7198,8 +7198,13 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta ZigType *most_aligned_union_member = union_type->data.unionation.most_aligned_union_member; ZigType *tag_type = union_type->data.unionation.tag_type; if (most_aligned_union_member == nullptr) { - union_type->llvm_type = get_llvm_type(g, tag_type); - union_type->llvm_di_type = get_llvm_di_type(g, tag_type); + if (tag_type == nullptr) { + union_type->llvm_type = g->builtin_types.entry_void->llvm_type; + union_type->llvm_di_type = g->builtin_types.entry_void->llvm_di_type; + } else { + union_type->llvm_type = get_llvm_type(g, tag_type); + union_type->llvm_di_type = get_llvm_di_type(g, tag_type); + } union_type->data.unionation.resolve_status = ResolveStatusLLVMFull; return; } diff --git a/test/stage1/behavior/union.zig b/test/stage1/behavior/union.zig index 7d6a8154ea3152f16a7ad26cd09f37c79fd27016..3df8aef3b022fe2edfde2d42ab76f665d16345b8 100644 --- a/test/stage1/behavior/union.zig +++ b/test/stage1/behavior/union.zig @@ -457,3 +457,13 @@ test "@unionInit can modify a pointer value" { value_ptr.* = @unionInit(UnionInitEnum, "Byte", 2); expect(value.Byte == 2); } + +test "union no tag with struct member" { + const Struct = struct { }; + const Union = union { + s : Struct, + pub fn foo(self: *@This()) void { } + }; + var u = Union { .s = Struct {} }; + u.foo(); +} -- 2.54.0 From 0c4d47c6d5a7d27ce54e8584da84613751df7dac Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 1 Sep 2019 23:35:58 -0400 Subject: [PATCH 05/23] add regression test for already fixed bug closes #2692 --- test/stage1/behavior.zig | 1 + test/stage1/behavior/bugs/2692.zig | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 test/stage1/behavior/bugs/2692.zig diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index f7152971a4e275f1d681478946e504ff4285caef..23ec3e53ce6adc17ff88fd28506d9a3f7fe9d85f 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -30,6 +30,7 @@ comptime { _ = @import("behavior/bugs/2114.zig"); _ = @import("behavior/bugs/2346.zig"); _ = @import("behavior/bugs/2578.zig"); + _ = @import("behavior/bugs/2692.zig"); _ = @import("behavior/bugs/3112.zig"); _ = @import("behavior/bugs/394.zig"); _ = @import("behavior/bugs/421.zig"); diff --git a/test/stage1/behavior/bugs/2692.zig b/test/stage1/behavior/bugs/2692.zig new file mode 100644 index 0000000000000000000000000000000000000000..267c3a131ae0c8180007b11e400e4ada9da59178 --- /dev/null +++ b/test/stage1/behavior/bugs/2692.zig @@ -0,0 +1,6 @@ +fn foo(a: []u8) void {} + +test "address of 0 length array" { + var pt: [0]u8 = undefined; + foo(&pt); +} -- 2.54.0 From 0fe28855c5a32b16dc092ab1d70efde38ef89a7b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 2 Sep 2019 11:32:22 -0400 Subject: [PATCH 06/23] add ability to specify darwin framework search dirs --- src/all_types.hpp | 1 + src/codegen.cpp | 1 + src/link.cpp | 6 ++++++ src/main.cpp | 9 +++++++++ std/build.zig | 15 +++++++++++++-- 5 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index d9e1dc44ca9eb35cf0f5ed9b75b7bbb4fe52985f..708db8848d805a45129e4797cebf4193a649fa16 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2003,6 +2003,7 @@ struct CodeGen { ZigList assembly_files; ZigList c_source_files; ZigList lib_dirs; + ZigList framework_dirs; ZigLibCInstallation *libc; diff --git a/src/codegen.cpp b/src/codegen.cpp index 890724d950737cd7b25601d485633c934949118d..74de8634cc895a44fee75a2eb8945088c30510b1 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -9803,6 +9803,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { cache_list_of_str(ch, g->llvm_argv, g->llvm_argv_len); cache_list_of_str(ch, g->clang_argv, g->clang_argv_len); cache_list_of_str(ch, g->lib_dirs.items, g->lib_dirs.length); + cache_list_of_str(ch, g->framework_dirs.items, g->framework_dirs.length); if (g->libc) { cache_buf(ch, &g->libc->include_dir); cache_buf(ch, &g->libc->sys_include_dir); diff --git a/src/link.cpp b/src/link.cpp index 8a1f889234d8d866165a81bdb2433cac4fefa457..5519f98fd22877c6cb0b814b9fbb684e81608ce8 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -2510,6 +2510,12 @@ static void construct_linker_job_macho(LinkJob *lj) { lj->args.append("dynamic_lookup"); } + for (size_t i = 0; i < g->framework_dirs.length; i += 1) { + const char *framework_dir = g->framework_dirs.at(i); + lj->args.append("-F"); + lj->args.append(framework_dir); + } + for (size_t i = 0; i < g->darwin_frameworks.length; i += 1) { lj->args.append("-framework"); lj->args.append(buf_ptr(g->darwin_frameworks.at(i))); diff --git a/src/main.cpp b/src/main.cpp index c0945ef18080252c216366672324241c0e722474..6f1ccd418c36e9cc20bb1ca8b962d2c384c7c7f3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -104,6 +104,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { " -rdynamic add all symbols to the dynamic symbol table\n" " -rpath [path] add directory to the runtime library search path\n" " --subsystem [subsystem] (windows) /SUBSYSTEM: to the linker\n" + " -F[dir] (darwin) add search path for frameworks\n" " -framework [name] (darwin) link against framework\n" " -mios-version-min [ver] (darwin) set iOS deployment target\n" " -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target\n" @@ -454,6 +455,7 @@ int main(int argc, char **argv) { ZigList lib_dirs = {0}; ZigList link_libs = {0}; ZigList forbidden_link_libs = {0}; + ZigList framework_dirs = {0}; ZigList frameworks = {0}; bool have_libc = false; const char *target_string = nullptr; @@ -686,6 +688,8 @@ int main(int argc, char **argv) { } else if (arg[1] == 'L' && arg[2] != 0) { // alias for --library-path lib_dirs.append(&arg[2]); + } else if (arg[1] == 'F' && arg[2] != 0) { + framework_dirs.append(&arg[2]); } else if (strcmp(arg, "--pkg-begin") == 0) { if (i + 2 >= argc) { fprintf(stderr, "Expected 2 arguments after --pkg-begin\n"); @@ -772,6 +776,8 @@ int main(int argc, char **argv) { main_pkg_path = buf_create_from_str(argv[i]); } else if (strcmp(arg, "--library-path") == 0 || strcmp(arg, "-L") == 0) { lib_dirs.append(argv[i]); + } else if (strcmp(arg, "-F") == 0) { + framework_dirs.append(argv[i]); } else if (strcmp(arg, "--library") == 0) { if (strcmp(argv[i], "c") == 0) have_libc = true; @@ -1153,6 +1159,9 @@ int main(int argc, char **argv) { for (size_t i = 0; i < lib_dirs.length; i += 1) { codegen_add_lib_dir(g, lib_dirs.at(i)); } + for (size_t i = 0; i < framework_dirs.length; i += 1) { + g->framework_dirs.append(framework_dirs.at(i)); + } for (size_t i = 0; i < link_libs.length; i += 1) { LinkLib *link_lib = codegen_add_link_lib(g, buf_create_from_str(link_libs.at(i))); link_lib->provided_explicitly = true; diff --git a/std/build.zig b/std/build.zig index 9393d72c15f84c4693894dbe0fbd09af8f022ac9..27715663f7d936c41dd1516bbda501b6d7d0cced 100644 --- a/std/build.zig +++ b/std/build.zig @@ -1228,6 +1228,7 @@ pub const LibExeObjStep = struct { name_only_filename: []const u8, strip: bool, lib_paths: ArrayList([]const u8), + framework_dirs: ArrayList([]const u8), frameworks: BufSet, verbose_link: bool, verbose_cc: bool, @@ -1341,6 +1342,7 @@ pub const LibExeObjStep = struct { .include_dirs = ArrayList(IncludeDir).init(builder.allocator), .link_objects = ArrayList(LinkObject).init(builder.allocator), .lib_paths = ArrayList([]const u8).init(builder.allocator), + .framework_dirs = ArrayList([]const u8).init(builder.allocator), .object_src = undefined, .build_options_contents = std.Buffer.initSize(builder.allocator, 0) catch unreachable, .c_std = Builder.CStd.C99, @@ -1614,6 +1616,10 @@ pub const LibExeObjStep = struct { self.lib_paths.append(path) catch unreachable; } + pub fn addFrameworkDir(self: *LibExeObjStep, dir_path: []const u8) void { + self.framework_dirs.append(dir_path) catch unreachable; + } + pub fn addPackagePath(self: *LibExeObjStep, name: []const u8, pkg_index_path: []const u8) void { self.packages.append(Pkg{ .name = name, @@ -1860,8 +1866,8 @@ pub const LibExeObjStep = struct { } for (self.lib_paths.toSliceConst()) |lib_path| { - zig_args.append("--library-path") catch unreachable; - zig_args.append(lib_path) catch unreachable; + try zig_args.append("-L"); + try zig_args.append(lib_path); } if (self.need_system_paths and self.target == Target.Native) { @@ -1882,6 +1888,11 @@ pub const LibExeObjStep = struct { } if (self.target.isDarwin()) { + for (self.framework_dirs.toSliceConst()) |dir| { + try zig_args.append("-F"); + try zig_args.append(dir); + } + var it = self.frameworks.iterator(); while (it.next()) |entry| { zig_args.append("-framework") catch unreachable; -- 2.54.0 From d291d3c8c00450e31b7cce15eae43db265361186 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 2 Sep 2019 13:07:44 -0400 Subject: [PATCH 07/23] fix using @typeOf on a generic function call --- src/ir.cpp | 58 ++++++++++++++++++------------- test/stage1/behavior/async_fn.zig | 25 +++++++++++++ 2 files changed, 58 insertions(+), 25 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index e1c7bb37fee31d8a05add4e82d4484c27c641712..3727e87915ad571f17e08547afcd25e56abad04a 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -15648,6 +15648,31 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source return &store_ptr->base; } +static IrInstruction *analyze_casted_new_stack(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, + ZigFn *fn_entry) +{ + if (call_instruction->new_stack == nullptr) + return nullptr; + + IrInstruction *new_stack = call_instruction->new_stack->child; + if (type_is_invalid(new_stack->value.type)) + return ira->codegen->invalid_instruction; + + if (call_instruction->is_async_call_builtin && + fn_entry != nullptr && new_stack->value.type->id == ZigTypeIdPointer && + new_stack->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame) + { + ZigType *needed_frame_type = get_pointer_to_type(ira->codegen, + get_fn_frame_type(ira->codegen, fn_entry), false); + return ir_implicit_cast(ira, new_stack, needed_frame_type); + } else { + ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, + false, false, PtrLenUnknown, target_fn_align(ira->codegen->zig_target), 0, 0, false); + ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr); + return ir_implicit_cast(ira, new_stack, u8_slice); + } +} + static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref, IrInstruction *first_arg_ptr, bool comptime_fn_call, FnInline fn_inline) @@ -15826,31 +15851,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c return ir_finish_anal(ira, new_instruction); } - IrInstruction *casted_new_stack = nullptr; - if (call_instruction->new_stack != nullptr) { - IrInstruction *new_stack = call_instruction->new_stack->child; - if (type_is_invalid(new_stack->value.type)) - return ira->codegen->invalid_instruction; - - if (call_instruction->is_async_call_builtin && - fn_entry != nullptr && new_stack->value.type->id == ZigTypeIdPointer && - new_stack->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame) - { - ZigType *needed_frame_type = get_pointer_to_type(ira->codegen, - get_fn_frame_type(ira->codegen, fn_entry), false); - casted_new_stack = ir_implicit_cast(ira, new_stack, needed_frame_type); - if (type_is_invalid(casted_new_stack->value.type)) - return ira->codegen->invalid_instruction; - } else { - ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, - false, false, PtrLenUnknown, target_fn_align(ira->codegen->zig_target), 0, 0, false); - ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr); - casted_new_stack = ir_implicit_cast(ira, new_stack, u8_slice); - if (type_is_invalid(casted_new_stack->value.type)) - return ira->codegen->invalid_instruction; - } - } - if (fn_type->data.fn.is_generic) { if (!fn_entry) { ir_add_error(ira, call_instruction->fn_ref, @@ -16063,6 +16063,10 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c parent_fn_entry->calls_or_awaits_errorable_fn = true; } + IrInstruction *casted_new_stack = analyze_casted_new_stack(ira, call_instruction, impl_fn); + if (casted_new_stack != nullptr && type_is_invalid(casted_new_stack->value.type)) + return ira->codegen->invalid_instruction; + size_t impl_param_count = impl_fn_type_id->param_count; if (call_instruction->is_async) { IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry, @@ -16211,6 +16215,10 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c return ira->codegen->invalid_instruction; } + IrInstruction *casted_new_stack = analyze_casted_new_stack(ira, call_instruction, fn_entry); + if (casted_new_stack != nullptr && type_is_invalid(casted_new_stack->value.type)) + return ira->codegen->invalid_instruction; + if (call_instruction->is_async) { IrInstruction *result = ir_analyze_async_call(ira, call_instruction, fn_entry, fn_type, fn_ref, casted_args, call_param_count, casted_new_stack); diff --git a/test/stage1/behavior/async_fn.zig b/test/stage1/behavior/async_fn.zig index 005a790f5fd81be2a781077563ca7d9bc26050fb..605a725e4b5f5ab4cb2cb59e82750ebebe99894c 100644 --- a/test/stage1/behavior/async_fn.zig +++ b/test/stage1/behavior/async_fn.zig @@ -1031,3 +1031,28 @@ test "@typeOf an async function call of generic fn with error union type" { }; _ = async S.func(i32); } + +test "using @typeOf on a generic function call" { + const S = struct { + var global_frame: anyframe = undefined; + var global_ok = false; + + var buf: [100]u8 align(16) = undefined; + + fn amain(x: var) void { + if (x == 0) { + global_ok = true; + return; + } + suspend { + global_frame = @frame(); + } + const F = @typeOf(async amain(x - 1)); + const frame = @intToPtr(*F, @ptrToInt(&buf)); + return await @asyncCall(frame, {}, amain, x - 1); + } + }; + _ = async S.amain(u32(1)); + resume S.global_frame; + expect(S.global_ok); +} -- 2.54.0 From ab4cba14c8aac7151b4c10094fea4211694da145 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 2 Sep 2019 14:35:41 -0400 Subject: [PATCH 08/23] fix recursive call of await @asyncCall with struct return type --- src/ir.cpp | 22 ++++++++++--------- test/stage1/behavior/async_fn.zig | 36 +++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 3727e87915ad571f17e08547afcd25e56abad04a..01066e51c30e80ddd06c751e85c2f372e3d792ba 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -330,6 +330,8 @@ static bool ir_should_inline(IrExecutable *exec, Scope *scope) { while (scope != nullptr) { if (scope->id == ScopeIdCompTime) return true; + if (scope->id == ScopeIdTypeOf) + return false; if (scope->id == ScopeIdFnDef) break; scope = scope->parent; @@ -16075,11 +16077,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c } IrInstruction *result_loc; - if (call_instruction->is_async_call_builtin) { - result_loc = get_async_call_result_loc(ira, call_instruction, impl_fn_type_id->return_type); - if (result_loc != nullptr && type_is_invalid(result_loc->value.type)) - return ira->codegen->invalid_instruction; - } else if (handle_is_ptr(impl_fn_type_id->return_type)) { + if (handle_is_ptr(impl_fn_type_id->return_type)) { result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, impl_fn_type_id->return_type, nullptr, true, true, false); if (result_loc != nullptr) { @@ -16091,6 +16089,10 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c result_loc = nullptr; } } + } else if (call_instruction->is_async_call_builtin) { + result_loc = get_async_call_result_loc(ira, call_instruction, impl_fn_type_id->return_type); + if (result_loc != nullptr && type_is_invalid(result_loc->value.type)) + return ira->codegen->invalid_instruction; } else { result_loc = nullptr; } @@ -16231,11 +16233,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c } IrInstruction *result_loc; - if (call_instruction->is_async_call_builtin) { - result_loc = get_async_call_result_loc(ira, call_instruction, return_type); - if (result_loc != nullptr && type_is_invalid(result_loc->value.type)) - return ira->codegen->invalid_instruction; - } else if (handle_is_ptr(return_type)) { + if (handle_is_ptr(return_type)) { result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, return_type, nullptr, true, true, false); if (result_loc != nullptr) { @@ -16247,6 +16245,10 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c result_loc = nullptr; } } + } else if (call_instruction->is_async_call_builtin) { + result_loc = get_async_call_result_loc(ira, call_instruction, return_type); + if (result_loc != nullptr && type_is_invalid(result_loc->value.type)) + return ira->codegen->invalid_instruction; } else { result_loc = nullptr; } diff --git a/test/stage1/behavior/async_fn.zig b/test/stage1/behavior/async_fn.zig index 605a725e4b5f5ab4cb2cb59e82750ebebe99894c..ad8e949f8b193dbc93659ae60c29f49c9d0b366a 100644 --- a/test/stage1/behavior/async_fn.zig +++ b/test/stage1/behavior/async_fn.zig @@ -1056,3 +1056,39 @@ test "using @typeOf on a generic function call" { resume S.global_frame; expect(S.global_ok); } + +test "recursive call of await @asyncCall with struct return type" { + const S = struct { + var global_frame: anyframe = undefined; + var global_ok = false; + + var buf: [100]u8 align(16) = undefined; + + fn amain(x: var) Foo { + if (x == 0) { + global_ok = true; + return Foo{ .x = 1, .y = 2, .z = 3 }; + } + suspend { + global_frame = @frame(); + } + const F = @typeOf(async amain(x - 1)); + const frame = @intToPtr(*F, @ptrToInt(&buf)); + return await @asyncCall(frame, {}, amain, x - 1); + } + + const Foo = struct { + x: u64, + y: u64, + z: u64, + }; + }; + var res: S.Foo = undefined; + var frame: @typeOf(async S.amain(u32(1))) = undefined; + _ = @asyncCall(&frame, &res, S.amain, u32(1)); + resume S.global_frame; + expect(S.global_ok); + expect(res.x == 1); + expect(res.y == 2); + expect(res.z == 3); +} -- 2.54.0 From 4a5b0cde1330e0410612838a42dad62cc30b0e92 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 2 Sep 2019 20:28:25 -0400 Subject: [PATCH 09/23] fix const result loc, runtime if cond, else unreachable Closes #2791. See that issue for more details; I documented the debugging process quite thoroughly on this one. --- src/codegen.cpp | 9 +++++++++ test/stage1/behavior/if.zig | 11 +++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/codegen.cpp b/src/codegen.cpp index 74de8634cc895a44fee75a2eb8945088c30510b1..0b51df1e82c8430dd12e64124908017da64ed054 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3522,6 +3522,15 @@ static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, Ir assert(ptr_type->id == ZigTypeIdPointer); if (!type_has_bits(ptr_type)) return nullptr; + if (instruction->ptr->ref_count == 0) { + // In this case, this StorePtr instruction should be elided. Something happened like this: + // var t = true; + // const x = if (t) Num.Two else unreachable; + // The if condition is a runtime value, so the StorePtr for `x = Num.Two` got generated + // (this instruction being rendered) but because of `else unreachable` the result ended + // up being a comptime const value. + return nullptr; + } bool have_init_expr = !value_is_all_undef(&instruction->value->value); if (have_init_expr) { diff --git a/test/stage1/behavior/if.zig b/test/stage1/behavior/if.zig index 5f92962957d7364d2d059f37f9587ba7629274e5..70712ea85a6f843d3f034ce397daf860377e8ce2 100644 --- a/test/stage1/behavior/if.zig +++ b/test/stage1/behavior/if.zig @@ -63,3 +63,14 @@ test "labeled break inside comptime if inside runtime if" { } expect(answer == 42); } + +test "const result loc, runtime if cond, else unreachable" { + const Num = enum { + One, + Two, + }; + + var t = true; + const x = if (t) Num.Two else unreachable; + if (x != .Two) @compileError("bad"); +} -- 2.54.0 From 00d82e34df92c181d20064c0c2f80feaba9dab03 Mon Sep 17 00:00:00 2001 From: Michael Dusan Date: Mon, 2 Sep 2019 17:45:30 -0400 Subject: [PATCH 10/23] cmake: improve building without git repository - quiet `fatal: not a git repository` message - if git probe fails skip ZIG_VERSION modification --- CMakeLists.txt | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index beb4ac671c506f057c4d4fbfb607cfda58d2aeda..f296f9dee491376b4d23261b17272a762275390b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,14 +23,18 @@ find_program(GIT_EXE NAMES git) if(GIT_EXE) execute_process( COMMAND ${GIT_EXE} -C ${CMAKE_SOURCE_DIR} name-rev HEAD --tags --name-only --no-undefined --always + RESULT_VARIABLE EXIT_STATUS OUTPUT_VARIABLE ZIG_GIT_REV - OUTPUT_STRIP_TRAILING_WHITESPACE) - if(ZIG_GIT_REV MATCHES "\\^0$") - if(NOT("${ZIG_GIT_REV}" STREQUAL "${ZIG_VERSION}^0")) - message("WARNING: Tag does not match configured Zig version") + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET) + if(EXIT_STATUS EQUAL "0") + if(ZIG_GIT_REV MATCHES "\\^0$") + if(NOT("${ZIG_GIT_REV}" STREQUAL "${ZIG_VERSION}^0")) + message("WARNING: Tag does not match configured Zig version") + endif() + else() + set(ZIG_VERSION "${ZIG_VERSION}+${ZIG_GIT_REV}") endif() - else() - set(ZIG_VERSION "${ZIG_VERSION}+${ZIG_GIT_REV}") endif() endif() message("Configuring zig version ${ZIG_VERSION}") -- 2.54.0 From d74b8567cf6a81550831a9ea02f2cebcb4db9846 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 2 Sep 2019 21:22:35 -0400 Subject: [PATCH 11/23] omit prefix data for async functions sometimes When `@frameSize` is never called, and `@asyncCall` on a runtime-known pointer is never used, no prefix data for async functions is needed. Related: #3160 --- src/all_types.hpp | 1 + src/codegen.cpp | 5 ++++- src/ir.cpp | 3 +++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 708db8848d805a45129e4797cebf4193a649fa16..1a97cf281469d3bc3ae845cb99d405c2ff000f40 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1989,6 +1989,7 @@ struct CodeGen { bool system_linker_hack; bool reported_bad_link_libc_error; bool is_dynamic; // shared library rather than static library. dynamic musl rather than static musl. + bool need_frame_size_prefix_data; //////////////////////////// Participates in Input Parameter Cache Hash /////// Note: there is a separate cache hash for builtin.zig, when adding fields, diff --git a/src/codegen.cpp b/src/codegen.cpp index 0b51df1e82c8430dd12e64124908017da64ed054..b694923873a51f8a8f206e282dfecf6558c94f19 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3775,6 +3775,7 @@ static void render_async_var_decls(CodeGen *g, Scope *scope) { } static LLVMValueRef gen_frame_size(CodeGen *g, LLVMValueRef fn_val) { + assert(g->need_frame_size_prefix_data); LLVMTypeRef usize_llvm_type = g->builtin_types.entry_usize->llvm_type; LLVMTypeRef ptr_usize_llvm_type = LLVMPointerType(usize_llvm_type, 0); LLVMValueRef casted_fn_val = LLVMBuildBitCast(g->builder, fn_val, ptr_usize_llvm_type, ""); @@ -7208,7 +7209,9 @@ static void do_code_gen(CodeGen *g) { LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; LLVMValueRef size_val = LLVMConstInt(usize_type_ref, fn_table_entry->frame_type->abi_size, false); - ZigLLVMFunctionSetPrefixData(fn_table_entry->llvm_value, size_val); + if (g->need_frame_size_prefix_data) { + ZigLLVMFunctionSetPrefixData(fn_table_entry->llvm_value, size_val); + } if (!g->strip_debug_symbols) { AstNode *source_node = fn_table_entry->proto_node; diff --git a/src/ir.cpp b/src/ir.cpp index 01066e51c30e80ddd06c751e85c2f372e3d792ba..e3b440d0f5c3a55630be16513467887ca005032b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -15671,6 +15671,7 @@ static IrInstruction *analyze_casted_new_stack(IrAnalyze *ira, IrInstructionCall ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, false, false, PtrLenUnknown, target_fn_align(ira->codegen->zig_target), 0, 0, false); ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr); + ira->codegen->need_frame_size_prefix_data = true; return ir_implicit_cast(ira, new_stack, u8_slice); } } @@ -22533,6 +22534,8 @@ static IrInstruction *ir_analyze_instruction_frame_size(IrAnalyze *ira, IrInstru return ira->codegen->invalid_instruction; } + ira->codegen->need_frame_size_prefix_data = true; + IrInstruction *result = ir_build_frame_size_gen(&ira->new_irb, instruction->base.scope, instruction->base.source_node, fn); result->value.type = ira->codegen->builtin_types.entry_usize; -- 2.54.0 From a19e73d8ae0bc5b7ac19b1bc72aa1fdb8f86d80f Mon Sep 17 00:00:00 2001 From: Michael Dusan Date: Mon, 27 May 2019 20:07:05 -0400 Subject: [PATCH 12/23] test: add compare-panic `zig build test-compare-panic` Create basic tests to compare panic output. The address field is replaced by a symbolic constant and each expected output is specific to os. Tests will only run for explicitly defined platforms. see also #2485 --- build.zig | 1 + test/compare_panic.zig | 277 +++++++++++++++++++++++++++++++++++++++++ test/tests.zig | 210 +++++++++++++++++++++++++++++++ 3 files changed, 488 insertions(+) create mode 100644 test/compare_panic.zig diff --git a/build.zig b/build.zig index 45758d4075371d16aff83a288d253d879fb5c347..cc0405c21a8481fa0d3aa58306615032a5a4fdc6 100644 --- a/build.zig +++ b/build.zig @@ -138,6 +138,7 @@ pub fn build(b: *Builder) !void { test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes)); test_step.dependOn(tests.addStandaloneTests(b, test_filter, modes)); + test_step.dependOn(tests.addComparePanicTests(b, test_filter, modes)); test_step.dependOn(tests.addCliTests(b, test_filter, modes)); test_step.dependOn(tests.addCompileErrorTests(b, test_filter, modes)); test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes)); diff --git a/test/compare_panic.zig b/test/compare_panic.zig new file mode 100644 index 0000000000000000000000000000000000000000..3c71b9626a97b947e1615cc717b86808fa5aa264 --- /dev/null +++ b/test/compare_panic.zig @@ -0,0 +1,277 @@ +const builtin = @import("builtin"); +const std = @import("std"); +const os = std.os; +const tests = @import("tests.zig"); + +pub fn addCases(cases: *tests.ComparePanicContext) void { + const source_return = + \\const std = @import("std"); + \\ + \\pub fn main() !void { + \\ return error.TheSkyIsFalling; + \\} + ; + const source_try_return = + \\const std = @import("std"); + \\ + \\fn foo() !void { + \\ return error.TheSkyIsFalling; + \\} + \\ + \\pub fn main() !void { + \\ try foo(); + \\} + ; + const source_try_try_return_return = + \\const std = @import("std"); + \\ + \\fn foo() !void { + \\ try bar(); + \\} + \\ + \\fn bar() !void { + \\ return make_error(); + \\} + \\ + \\fn make_error() !void { + \\ return error.TheSkyIsFalling; + \\} + \\ + \\pub fn main() !void { + \\ try foo(); + \\} + ; + switch (builtin.os) { + .linux => { + cases.addCase( + "return", + source_return, + [][]const u8{ + // debug + \\error: TheSkyIsFalling + \\source.zig:4:5: [address] in main (test) + \\ + , + // release-safe + \\error: TheSkyIsFalling + \\source.zig:4:5: [address] in std.special.posixCallMainAndExit (test) + \\ + , + // release-fast + \\error: TheSkyIsFalling + \\ + , + // release-small + \\error: TheSkyIsFalling + \\ + }, + ); + cases.addCase( + "try return", + source_try_return, + [][]const u8{ + // debug + \\error: TheSkyIsFalling + \\source.zig:4:5: [address] in foo (test) + \\source.zig:8:5: [address] in main (test) + \\ + , + // release-safe + \\error: TheSkyIsFalling + \\source.zig:4:5: [address] in std.special.posixCallMainAndExit (test) + \\source.zig:8:5: [address] in std.special.posixCallMainAndExit (test) + \\ + , + // release-fast + \\error: TheSkyIsFalling + \\ + , + // release-small + \\error: TheSkyIsFalling + \\ + }, + ); + cases.addCase( + "try try return return", + source_try_try_return_return, + [][]const u8{ + // debug + \\error: TheSkyIsFalling + \\source.zig:12:5: [address] in make_error (test) + \\source.zig:8:5: [address] in bar (test) + \\source.zig:4:5: [address] in foo (test) + \\source.zig:16:5: [address] in main (test) + \\ + , + // release-safe + \\error: TheSkyIsFalling + \\source.zig:12:5: [address] in std.special.posixCallMainAndExit (test) + \\source.zig:8:5: [address] in std.special.posixCallMainAndExit (test) + \\source.zig:4:5: [address] in std.special.posixCallMainAndExit (test) + \\source.zig:16:5: [address] in std.special.posixCallMainAndExit (test) + \\ + , + // release-fast + \\error: TheSkyIsFalling + \\ + , + // release-small + \\error: TheSkyIsFalling + \\ + }, + ); + }, + .macosx => { + cases.addCase( + "return", + source_return, + [][]const u8{ + // debug + \\error: TheSkyIsFalling + \\source.zig:4:5: [address] in _main.0 (test.o) + \\ + , + // release-safe + \\error: TheSkyIsFalling + \\source.zig:4:5: [address] in _main (test.o) + \\ + , + // release-fast + \\error: TheSkyIsFalling + \\ + , + // release-small + \\error: TheSkyIsFalling + \\ + }, + ); + cases.addCase( + "try return", + source_try_return, + [][]const u8{ + // debug + \\error: TheSkyIsFalling + \\source.zig:4:5: [address] in _foo (test.o) + \\source.zig:8:5: [address] in _main.0 (test.o) + \\ + , + // release-safe + \\error: TheSkyIsFalling + \\source.zig:4:5: [address] in _main (test.o) + \\source.zig:8:5: [address] in _main (test.o) + \\ + , + // release-fast + \\error: TheSkyIsFalling + \\ + , + // release-small + \\error: TheSkyIsFalling + \\ + }, + ); + cases.addCase( + "try try return return", + source_try_try_return_return, + [][]const u8{ + // debug + \\error: TheSkyIsFalling + \\source.zig:12:5: [address] in _make_error (test.o) + \\source.zig:8:5: [address] in _bar (test.o) + \\source.zig:4:5: [address] in _foo (test.o) + \\source.zig:16:5: [address] in _main.0 (test.o) + \\ + , + // release-safe + \\error: TheSkyIsFalling + \\source.zig:12:5: [address] in _main (test.o) + \\source.zig:8:5: [address] in _main (test.o) + \\source.zig:4:5: [address] in _main (test.o) + \\source.zig:16:5: [address] in _main (test.o) + \\ + , + // release-fast + \\error: TheSkyIsFalling + \\ + , + // release-small + \\error: TheSkyIsFalling + \\ + }, + ); + }, + .windows => { + cases.addCase( + "return", + source_return, + [][]const u8{ + // debug + \\error: TheSkyIsFalling + \\source.zig:4:5: [address] in main (test.obj) + \\ + , + // release-safe + // --disabled-- results in segmenetation fault + "" + , + // release-fast + \\error: TheSkyIsFalling + \\ + , + // release-small + \\error: TheSkyIsFalling + \\ + }, + ); + cases.addCase( + "try return", + source_try_return, + [][]const u8{ + // debug + \\error: TheSkyIsFalling + \\source.zig:4:5: [address] in foo (test.obj) + \\source.zig:8:5: [address] in main (test.obj) + \\ + , + // release-safe + // --disabled-- results in segmenetation fault + "" + , + // release-fast + \\error: TheSkyIsFalling + \\ + , + // release-small + \\error: TheSkyIsFalling + \\ + }, + ); + cases.addCase( + "try try return return", + source_try_try_return_return, + [][]const u8{ + // debug + \\error: TheSkyIsFalling + \\source.zig:12:5: [address] in make_error (test.obj) + \\source.zig:8:5: [address] in bar (test.obj) + \\source.zig:4:5: [address] in foo (test.obj) + \\source.zig:16:5: [address] in main (test.obj) + \\ + , + // release-safe + // --disabled-- results in segmenetation fault + "" + , + // release-fast + \\error: TheSkyIsFalling + \\ + , + // release-small + \\error: TheSkyIsFalling + \\ + }, + ); + }, + else => {}, + } +} diff --git a/test/tests.zig b/test/tests.zig index f7ef05d3cd51de041cb2b97784dbba5c44ea1cff..1bb9e417e5ab41f6f5c0053571726000b0b19953 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -16,6 +16,7 @@ const LibExeObjStep = build.LibExeObjStep; const compare_output = @import("compare_output.zig"); const standalone = @import("standalone.zig"); +const compare_panic = @import("compare_panic.zig"); const compile_errors = @import("compile_errors.zig"); const assemble_and_link = @import("assemble_and_link.zig"); const runtime_safety = @import("runtime_safety.zig"); @@ -57,6 +58,21 @@ pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8, modes: return cases.step; } +pub fn addComparePanicTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { + const cases = b.allocator.create(ComparePanicContext) catch unreachable; + cases.* = ComparePanicContext{ + .b = b, + .step = b.step("test-compare-panic", "Run the compare panic tests"), + .test_index = 0, + .test_filter = test_filter, + .modes = modes, + }; + + compare_panic.addCases(cases); + + return cases.step; +} + pub fn addRuntimeSafetyTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { const cases = b.allocator.create(CompareOutputContext) catch unreachable; cases.* = CompareOutputContext{ @@ -549,6 +565,200 @@ pub const CompareOutputContext = struct { } }; +pub const ComparePanicContext = struct { + b: *build.Builder, + step: *build.Step, + test_index: usize, + test_filter: ?[]const u8, + modes: []const Mode, + + const Expect = [@typeInfo(Mode).Enum.fields.len][]const u8; + + pub fn addCase( + self: *ComparePanicContext, + name: []const u8, + source: []const u8, + expect: Expect, + ) void { + const b = self.b; + + const source_pathname = fs.path.join( + b.allocator, + [][]const u8{ b.cache_root, "source.zig" }, + ) catch unreachable; + + for (self.modes) |mode| { + const expect_for_mode = expect[@enumToInt(mode)]; + if (expect_for_mode.len == 0) continue; + + const annotated_case_name = fmt.allocPrint(self.b.allocator, "{} {} ({})", "compare-panic", name, @tagName(mode)) catch unreachable; + if (self.test_filter) |filter| { + if (mem.indexOf(u8, annotated_case_name, filter) == null) continue; + } + + const exe = b.addExecutable("test", source_pathname); + exe.setBuildMode(mode); + + const write_source = b.addWriteFile(source_pathname, source); + exe.step.dependOn(&write_source.step); + + const run_and_compare = RunAndCompareStep.create( + self, + exe, + annotated_case_name, + mode, + expect_for_mode, + ); + + self.step.dependOn(&run_and_compare.step); + } + } + + const RunAndCompareStep = struct { + step: build.Step, + context: *ComparePanicContext, + exe: *LibExeObjStep, + name: []const u8, + mode: Mode, + expect_output: []const u8, + test_index: usize, + + pub fn create( + context: *ComparePanicContext, + exe: *LibExeObjStep, + name: []const u8, + mode: Mode, + expect_output: []const u8, + ) *RunAndCompareStep { + const allocator = context.b.allocator; + const ptr = allocator.create(RunAndCompareStep) catch unreachable; + ptr.* = RunAndCompareStep{ + .step = build.Step.init("PanicCompareOutputStep", allocator, make), + .context = context, + .exe = exe, + .name = name, + .mode = mode, + .expect_output = expect_output, + .test_index = context.test_index, + }; + ptr.step.dependOn(&exe.step); + context.test_index += 1; + return ptr; + } + + fn make(step: *build.Step) !void { + const self = @fieldParentPtr(RunAndCompareStep, "step", step); + const b = self.context.b; + + const full_exe_path = self.exe.getOutputPath(); + var args = ArrayList([]const u8).init(b.allocator); + defer args.deinit(); + args.append(full_exe_path) catch unreachable; + + warn("Test {}/{} {}...", self.test_index + 1, self.context.test_index, self.name); + + const child = std.ChildProcess.init(args.toSliceConst(), b.allocator) catch unreachable; + defer child.deinit(); + + child.stdin_behavior = .Ignore; + child.stdout_behavior = .Pipe; + child.stderr_behavior = .Pipe; + child.env_map = b.env_map; + + child.spawn() catch |err| debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err)); + + var stdout = Buffer.initNull(b.allocator); + var stderr = Buffer.initNull(b.allocator); + + var stdout_file_in_stream = child.stdout.?.inStream(); + var stderr_file_in_stream = child.stderr.?.inStream(); + + stdout_file_in_stream.stream.readAllBuffer(&stdout, max_stdout_size) catch unreachable; + stderr_file_in_stream.stream.readAllBuffer(&stderr, max_stdout_size) catch unreachable; + + const term = child.wait() catch |err| { + debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err)); + }; + + switch (term) { + .Exited => |code| { + const expect_code: u32 = 1; + if (code != expect_code) { + warn("Process {} exited with error code {} but expected code {}\n", full_exe_path, code, expect_code); + printInvocation(args.toSliceConst()); + return error.TestFailed; + } + }, + .Signal => |signum| { + warn("Process {} terminated on signal {}\n", full_exe_path, signum); + printInvocation(args.toSliceConst()); + return error.TestFailed; + }, + .Stopped => |signum| { + warn("Process {} stopped on signal {}\n", full_exe_path, signum); + printInvocation(args.toSliceConst()); + return error.TestFailed; + }, + .Unknown => |code| { + warn("Process {} terminated unexpectedly with error code {}\n", full_exe_path, code); + printInvocation(args.toSliceConst()); + return error.TestFailed; + }, + } + + // process result + // - keep only basename of source file path + // - replace address with symbolic string + // - skip empty lines + 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]; + var it = mem.separate(bytes, "\n"); + process_lines: while (it.next()) |line| { + if (line.len == 0) continue; + const delims = []const []const u8{ ":", ":", ":", " in " }; + var marks = []usize{0} ** 4; + // offset search past `[drive]:` on windows + var pos: usize = if (builtin.os == .windows) 2 else 0; + for (delims) |delim, i| { + marks[i] = mem.indexOfPos(u8, line, pos, delim) orelse { + try buf.append(line); + try buf.append("\n"); + continue :process_lines; + }; + pos = marks[i] + delim.len; + } + pos = mem.lastIndexOfScalar(u8, line[0..marks[0]], fs.path.sep) orelse { + try buf.append(line); + try buf.append("\n"); + continue :process_lines; + }; + try buf.append(line[pos + 1 .. marks[2] + delims[2].len]); + try buf.append(" [address]"); + try buf.append(line[marks[3]..]); + try buf.append("\n"); + } + break :got_result buf.toOwnedSlice(); + }; + + if (!mem.eql(u8, self.expect_output, got)) { + warn( + \\ + \\========= Expected this output: ========= + \\{} + \\================================================ + \\{} + \\ + , self.expect_output, got); + return error.TestFailed; + } + warn("OK\n"); + } + }; +}; + pub const CompileErrorContext = struct { b: *build.Builder, step: *build.Step, -- 2.54.0 From 1fd24791a7ea74260c86212e65b13cafd6243863 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 3 Sep 2019 10:05:19 -0400 Subject: [PATCH 13/23] rename compare-panic to compare-stack-traces --- build.zig | 4 +- .../{compare_panic.zig => compare_traces.zig} | 173 +++++++++--------- test/tests.zig | 28 +-- 3 files changed, 101 insertions(+), 104 deletions(-) rename test/{compare_panic.zig => compare_traces.zig} (63%) diff --git a/build.zig b/build.zig index cc0405c21a8481fa0d3aa58306615032a5a4fdc6..f8c095e8250f4c48a62a403537d8c3425eb1abc8 100644 --- a/build.zig +++ b/build.zig @@ -138,13 +138,13 @@ pub fn build(b: *Builder) !void { test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes)); test_step.dependOn(tests.addStandaloneTests(b, test_filter, modes)); - test_step.dependOn(tests.addComparePanicTests(b, test_filter, modes)); + test_step.dependOn(tests.addCompareStackTracesTests(b, test_filter, modes)); test_step.dependOn(tests.addCliTests(b, test_filter, modes)); - test_step.dependOn(tests.addCompileErrorTests(b, test_filter, modes)); test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes)); test_step.dependOn(tests.addRuntimeSafetyTests(b, test_filter, modes)); test_step.dependOn(tests.addTranslateCTests(b, test_filter)); test_step.dependOn(tests.addGenHTests(b, test_filter)); + test_step.dependOn(tests.addCompileErrorTests(b, test_filter, modes)); test_step.dependOn(docs_step); } diff --git a/test/compare_panic.zig b/test/compare_traces.zig similarity index 63% rename from test/compare_panic.zig rename to test/compare_traces.zig index 3c71b9626a97b947e1615cc717b86808fa5aa264..3de0fb680a650aa080064935effc55f90326d491 100644 --- a/test/compare_panic.zig +++ b/test/compare_traces.zig @@ -3,7 +3,7 @@ const std = @import("std"); const os = std.os; const tests = @import("tests.zig"); -pub fn addCases(cases: *tests.ComparePanicContext) void { +pub fn addCases(cases: *tests.CompareStackTracesContext) void { const source_return = \\const std = @import("std"); \\ @@ -46,77 +46,77 @@ pub fn addCases(cases: *tests.ComparePanicContext) void { cases.addCase( "return", source_return, - [][]const u8{ - // debug - \\error: TheSkyIsFalling + [_][]const u8{ + // debug + \\error: TheSkyIsFalling \\source.zig:4:5: [address] in main (test) \\ , - // release-safe - \\error: TheSkyIsFalling + // release-safe + \\error: TheSkyIsFalling \\source.zig:4:5: [address] in std.special.posixCallMainAndExit (test) \\ , - // release-fast - \\error: TheSkyIsFalling + // release-fast + \\error: TheSkyIsFalling \\ , - // release-small - \\error: TheSkyIsFalling + // release-small + \\error: TheSkyIsFalling \\ }, ); cases.addCase( "try return", source_try_return, - [][]const u8{ - // debug - \\error: TheSkyIsFalling + [_][]const u8{ + // debug + \\error: TheSkyIsFalling \\source.zig:4:5: [address] in foo (test) \\source.zig:8:5: [address] in main (test) \\ , - // release-safe - \\error: TheSkyIsFalling + // release-safe + \\error: TheSkyIsFalling \\source.zig:4:5: [address] in std.special.posixCallMainAndExit (test) \\source.zig:8:5: [address] in std.special.posixCallMainAndExit (test) \\ , - // release-fast - \\error: TheSkyIsFalling + // release-fast + \\error: TheSkyIsFalling \\ , - // release-small - \\error: TheSkyIsFalling + // release-small + \\error: TheSkyIsFalling \\ }, ); cases.addCase( "try try return return", source_try_try_return_return, - [][]const u8{ - // debug - \\error: TheSkyIsFalling + [_][]const u8{ + // debug + \\error: TheSkyIsFalling \\source.zig:12:5: [address] in make_error (test) \\source.zig:8:5: [address] in bar (test) \\source.zig:4:5: [address] in foo (test) \\source.zig:16:5: [address] in main (test) \\ , - // release-safe - \\error: TheSkyIsFalling + // release-safe + \\error: TheSkyIsFalling \\source.zig:12:5: [address] in std.special.posixCallMainAndExit (test) \\source.zig:8:5: [address] in std.special.posixCallMainAndExit (test) \\source.zig:4:5: [address] in std.special.posixCallMainAndExit (test) \\source.zig:16:5: [address] in std.special.posixCallMainAndExit (test) \\ , - // release-fast - \\error: TheSkyIsFalling + // release-fast + \\error: TheSkyIsFalling \\ , - // release-small - \\error: TheSkyIsFalling + // release-small + \\error: TheSkyIsFalling \\ }, ); @@ -125,77 +125,77 @@ pub fn addCases(cases: *tests.ComparePanicContext) void { cases.addCase( "return", source_return, - [][]const u8{ - // debug - \\error: TheSkyIsFalling + [_][]const u8{ + // debug + \\error: TheSkyIsFalling \\source.zig:4:5: [address] in _main.0 (test.o) \\ , - // release-safe - \\error: TheSkyIsFalling + // release-safe + \\error: TheSkyIsFalling \\source.zig:4:5: [address] in _main (test.o) \\ , - // release-fast - \\error: TheSkyIsFalling + // release-fast + \\error: TheSkyIsFalling \\ , - // release-small - \\error: TheSkyIsFalling + // release-small + \\error: TheSkyIsFalling \\ }, ); cases.addCase( "try return", source_try_return, - [][]const u8{ - // debug - \\error: TheSkyIsFalling + [_][]const u8{ + // debug + \\error: TheSkyIsFalling \\source.zig:4:5: [address] in _foo (test.o) \\source.zig:8:5: [address] in _main.0 (test.o) \\ , - // release-safe - \\error: TheSkyIsFalling + // release-safe + \\error: TheSkyIsFalling \\source.zig:4:5: [address] in _main (test.o) \\source.zig:8:5: [address] in _main (test.o) \\ , - // release-fast - \\error: TheSkyIsFalling + // release-fast + \\error: TheSkyIsFalling \\ , - // release-small - \\error: TheSkyIsFalling + // release-small + \\error: TheSkyIsFalling \\ }, ); cases.addCase( "try try return return", source_try_try_return_return, - [][]const u8{ - // debug - \\error: TheSkyIsFalling + [_][]const u8{ + // debug + \\error: TheSkyIsFalling \\source.zig:12:5: [address] in _make_error (test.o) \\source.zig:8:5: [address] in _bar (test.o) \\source.zig:4:5: [address] in _foo (test.o) \\source.zig:16:5: [address] in _main.0 (test.o) \\ , - // release-safe - \\error: TheSkyIsFalling + // release-safe + \\error: TheSkyIsFalling \\source.zig:12:5: [address] in _main (test.o) \\source.zig:8:5: [address] in _main (test.o) \\source.zig:4:5: [address] in _main (test.o) \\source.zig:16:5: [address] in _main (test.o) \\ , - // release-fast - \\error: TheSkyIsFalling + // release-fast + \\error: TheSkyIsFalling \\ , - // release-small - \\error: TheSkyIsFalling + // release-small + \\error: TheSkyIsFalling \\ }, ); @@ -204,70 +204,67 @@ pub fn addCases(cases: *tests.ComparePanicContext) void { cases.addCase( "return", source_return, - [][]const u8{ - // debug - \\error: TheSkyIsFalling + [_][]const u8{ + // debug + \\error: TheSkyIsFalling \\source.zig:4:5: [address] in main (test.obj) \\ , - // release-safe - // --disabled-- results in segmenetation fault - "" - , - // release-fast - \\error: TheSkyIsFalling + // release-safe + // --disabled-- results in segmenetation fault + "", + // release-fast + \\error: TheSkyIsFalling \\ , - // release-small - \\error: TheSkyIsFalling + // release-small + \\error: TheSkyIsFalling \\ }, ); cases.addCase( "try return", source_try_return, - [][]const u8{ - // debug - \\error: TheSkyIsFalling + [_][]const u8{ + // debug + \\error: TheSkyIsFalling \\source.zig:4:5: [address] in foo (test.obj) \\source.zig:8:5: [address] in main (test.obj) \\ , - // release-safe - // --disabled-- results in segmenetation fault - "" - , - // release-fast - \\error: TheSkyIsFalling + // release-safe + // --disabled-- results in segmenetation fault + "", + // release-fast + \\error: TheSkyIsFalling \\ , - // release-small - \\error: TheSkyIsFalling + // release-small + \\error: TheSkyIsFalling \\ }, ); cases.addCase( "try try return return", source_try_try_return_return, - [][]const u8{ - // debug - \\error: TheSkyIsFalling + [_][]const u8{ + // debug + \\error: TheSkyIsFalling \\source.zig:12:5: [address] in make_error (test.obj) \\source.zig:8:5: [address] in bar (test.obj) \\source.zig:4:5: [address] in foo (test.obj) \\source.zig:16:5: [address] in main (test.obj) \\ , - // release-safe - // --disabled-- results in segmenetation fault - "" - , - // release-fast - \\error: TheSkyIsFalling + // release-safe + // --disabled-- results in segmenetation fault + "", + // release-fast + \\error: TheSkyIsFalling \\ , - // release-small - \\error: TheSkyIsFalling + // release-small + \\error: TheSkyIsFalling \\ }, ); diff --git a/test/tests.zig b/test/tests.zig index 1bb9e417e5ab41f6f5c0053571726000b0b19953..754407df9a8aaae633b98b275a1923922e103d33 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -16,7 +16,7 @@ const LibExeObjStep = build.LibExeObjStep; const compare_output = @import("compare_output.zig"); const standalone = @import("standalone.zig"); -const compare_panic = @import("compare_panic.zig"); +const compare_panic = @import("compare_traces.zig"); const compile_errors = @import("compile_errors.zig"); const assemble_and_link = @import("assemble_and_link.zig"); const runtime_safety = @import("runtime_safety.zig"); @@ -58,11 +58,11 @@ pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8, modes: return cases.step; } -pub fn addComparePanicTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { - const cases = b.allocator.create(ComparePanicContext) catch unreachable; - cases.* = ComparePanicContext{ +pub fn addCompareStackTracesTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { + const cases = b.allocator.create(CompareStackTracesContext) catch unreachable; + cases.* = CompareStackTracesContext{ .b = b, - .step = b.step("test-compare-panic", "Run the compare panic tests"), + .step = b.step("test-compare-traces", "Run the compare stack traces tests"), .test_index = 0, .test_filter = test_filter, .modes = modes, @@ -565,7 +565,7 @@ pub const CompareOutputContext = struct { } }; -pub const ComparePanicContext = struct { +pub const CompareStackTracesContext = struct { b: *build.Builder, step: *build.Step, test_index: usize, @@ -575,7 +575,7 @@ pub const ComparePanicContext = struct { const Expect = [@typeInfo(Mode).Enum.fields.len][]const u8; pub fn addCase( - self: *ComparePanicContext, + self: *CompareStackTracesContext, name: []const u8, source: []const u8, expect: Expect, @@ -584,14 +584,14 @@ pub const ComparePanicContext = struct { const source_pathname = fs.path.join( b.allocator, - [][]const u8{ b.cache_root, "source.zig" }, + [_][]const u8{ b.cache_root, "source.zig" }, ) catch unreachable; for (self.modes) |mode| { const expect_for_mode = expect[@enumToInt(mode)]; if (expect_for_mode.len == 0) continue; - const annotated_case_name = fmt.allocPrint(self.b.allocator, "{} {} ({})", "compare-panic", name, @tagName(mode)) catch unreachable; + const annotated_case_name = fmt.allocPrint(self.b.allocator, "{} {} ({})", "compare-stack-traces", name, @tagName(mode)) catch unreachable; if (self.test_filter) |filter| { if (mem.indexOf(u8, annotated_case_name, filter) == null) continue; } @@ -616,7 +616,7 @@ pub const ComparePanicContext = struct { const RunAndCompareStep = struct { step: build.Step, - context: *ComparePanicContext, + context: *CompareStackTracesContext, exe: *LibExeObjStep, name: []const u8, mode: Mode, @@ -624,7 +624,7 @@ pub const ComparePanicContext = struct { test_index: usize, pub fn create( - context: *ComparePanicContext, + context: *CompareStackTracesContext, exe: *LibExeObjStep, name: []const u8, mode: Mode, @@ -633,7 +633,7 @@ pub const ComparePanicContext = struct { const allocator = context.b.allocator; const ptr = allocator.create(RunAndCompareStep) catch unreachable; ptr.* = RunAndCompareStep{ - .step = build.Step.init("PanicCompareOutputStep", allocator, make), + .step = build.Step.init("StackTraceCompareOutputStep", allocator, make), .context = context, .exe = exe, .name = name, @@ -718,8 +718,8 @@ pub const ComparePanicContext = struct { var it = mem.separate(bytes, "\n"); process_lines: while (it.next()) |line| { if (line.len == 0) continue; - const delims = []const []const u8{ ":", ":", ":", " in " }; - var marks = []usize{0} ** 4; + const delims = [_][]const u8{ ":", ":", ":", " in " }; + var marks = [_]usize{0} ** 4; // offset search past `[drive]:` on windows var pos: usize = if (builtin.os == .windows) 2 else 0; for (delims) |delim, i| { -- 2.54.0 From aba67ecf4475a72035b60dbc0284c2076600f2e1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 3 Sep 2019 10:08:39 -0400 Subject: [PATCH 14/23] rename test-compare-panic to test-stack-traces --- build.zig | 2 +- test/{compare_traces.zig => stack_traces.zig} | 2 +- test/tests.zig | 22 +++++++++---------- 3 files changed, 13 insertions(+), 13 deletions(-) rename test/{compare_traces.zig => stack_traces.zig} (99%) diff --git a/build.zig b/build.zig index f8c095e8250f4c48a62a403537d8c3425eb1abc8..21fa79e863c78cb2796ef6b210aefd2b8d028d07 100644 --- a/build.zig +++ b/build.zig @@ -138,7 +138,7 @@ pub fn build(b: *Builder) !void { test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes)); test_step.dependOn(tests.addStandaloneTests(b, test_filter, modes)); - test_step.dependOn(tests.addCompareStackTracesTests(b, test_filter, modes)); + test_step.dependOn(tests.addStackTraceTests(b, test_filter, modes)); test_step.dependOn(tests.addCliTests(b, test_filter, modes)); test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes)); test_step.dependOn(tests.addRuntimeSafetyTests(b, test_filter, modes)); diff --git a/test/compare_traces.zig b/test/stack_traces.zig similarity index 99% rename from test/compare_traces.zig rename to test/stack_traces.zig index 3de0fb680a650aa080064935effc55f90326d491..1a014f07cc221dde90bdd7734d47ebce3d433f70 100644 --- a/test/compare_traces.zig +++ b/test/stack_traces.zig @@ -3,7 +3,7 @@ const std = @import("std"); const os = std.os; const tests = @import("tests.zig"); -pub fn addCases(cases: *tests.CompareStackTracesContext) void { +pub fn addCases(cases: *tests.StackTracesContext) void { const source_return = \\const std = @import("std"); \\ diff --git a/test/tests.zig b/test/tests.zig index 754407df9a8aaae633b98b275a1923922e103d33..99ee5949c3546a66a52fe344ccfa21864ec163b8 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -16,7 +16,7 @@ const LibExeObjStep = build.LibExeObjStep; const compare_output = @import("compare_output.zig"); const standalone = @import("standalone.zig"); -const compare_panic = @import("compare_traces.zig"); +const stack_traces = @import("stack_traces.zig"); const compile_errors = @import("compile_errors.zig"); const assemble_and_link = @import("assemble_and_link.zig"); const runtime_safety = @import("runtime_safety.zig"); @@ -58,17 +58,17 @@ pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8, modes: return cases.step; } -pub fn addCompareStackTracesTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { - const cases = b.allocator.create(CompareStackTracesContext) catch unreachable; - cases.* = CompareStackTracesContext{ +pub fn addStackTraceTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { + const cases = b.allocator.create(StackTracesContext) catch unreachable; + cases.* = StackTracesContext{ .b = b, - .step = b.step("test-compare-traces", "Run the compare stack traces tests"), + .step = b.step("test-stack-traces", "Run the stack trace tests"), .test_index = 0, .test_filter = test_filter, .modes = modes, }; - compare_panic.addCases(cases); + stack_traces.addCases(cases); return cases.step; } @@ -565,7 +565,7 @@ pub const CompareOutputContext = struct { } }; -pub const CompareStackTracesContext = struct { +pub const StackTracesContext = struct { b: *build.Builder, step: *build.Step, test_index: usize, @@ -575,7 +575,7 @@ pub const CompareStackTracesContext = struct { const Expect = [@typeInfo(Mode).Enum.fields.len][]const u8; pub fn addCase( - self: *CompareStackTracesContext, + self: *StackTracesContext, name: []const u8, source: []const u8, expect: Expect, @@ -591,7 +591,7 @@ pub const CompareStackTracesContext = struct { const expect_for_mode = expect[@enumToInt(mode)]; if (expect_for_mode.len == 0) continue; - const annotated_case_name = fmt.allocPrint(self.b.allocator, "{} {} ({})", "compare-stack-traces", name, @tagName(mode)) catch unreachable; + const annotated_case_name = fmt.allocPrint(self.b.allocator, "{} {} ({})", "stack-trace", name, @tagName(mode)) catch unreachable; if (self.test_filter) |filter| { if (mem.indexOf(u8, annotated_case_name, filter) == null) continue; } @@ -616,7 +616,7 @@ pub const CompareStackTracesContext = struct { const RunAndCompareStep = struct { step: build.Step, - context: *CompareStackTracesContext, + context: *StackTracesContext, exe: *LibExeObjStep, name: []const u8, mode: Mode, @@ -624,7 +624,7 @@ pub const CompareStackTracesContext = struct { test_index: usize, pub fn create( - context: *CompareStackTracesContext, + context: *StackTracesContext, exe: *LibExeObjStep, name: []const u8, mode: Mode, -- 2.54.0 From e9530ce97bbbda9724dce3d6755217fd7880955c Mon Sep 17 00:00:00 2001 From: Vesa Kaihlavirta Date: Sun, 1 Sep 2019 13:27:26 +0300 Subject: [PATCH 15/23] Fix addition direction, remove superfluous loop counter, add tests --- std/fmt/parse_float.zig | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/std/fmt/parse_float.zig b/std/fmt/parse_float.zig index ce2cc70768f1b35ef39c2764c4330a0dbebaa5c1..d0a826a55ef62d60c978aabe4ed62d7b32639e51 100644 --- a/std/fmt/parse_float.zig +++ b/std/fmt/parse_float.zig @@ -110,9 +110,7 @@ fn convertRepr(comptime T: type, n: FloatRepr) T { q.shiftLeft1(s); // q = p << 1 r.shiftLeft1(q); // r = p << 2 s.shiftLeft1(r); // p = p << 3 - q.add(s); // p = (p << 3) + (p << 1) - - exp -= 1; + s.add(q); // p = (p << 3) + (p << 1) while (s.d2 & mask28 != 0) { q.shiftRight1(s); @@ -402,6 +400,13 @@ test "fmt.parseFloat" { expectEqual((try parseFloat(T, "+0")), 0.0); expectEqual((try parseFloat(T, "-0")), 0.0); + expectEqual((try parseFloat(T, "0e0")), 0); + expectEqual((try parseFloat(T, "2e3")), 2000.0); + expectEqual((try parseFloat(T, "1e0")), 1.0); + expectEqual((try parseFloat(T, "-2e3")), -2000.0); + expectEqual((try parseFloat(T, "-1e0")), -1.0); + expectEqual((try parseFloat(T, "1.234e3")), 1234); + expect(approxEq(T, try parseFloat(T, "3.141"), 3.141, epsilon)); expect(approxEq(T, try parseFloat(T, "-3.141"), -3.141, epsilon)); @@ -413,6 +418,9 @@ test "fmt.parseFloat" { expectEqual((try parseFloat(T, "-INF")), -std.math.inf(T)); if (T != f16) { + expect(approxEq(T, try parseFloat(T, "1e-2"), 0.01, epsilon)); + expect(approxEq(T, try parseFloat(T, "1234e-2"), 12.34, epsilon)); + expect(approxEq(T, try parseFloat(T, "123142.1"), 123142.1, epsilon)); expect(approxEq(T, try parseFloat(T, "-123142.1124"), T(-123142.1124), epsilon)); expect(approxEq(T, try parseFloat(T, "0.7062146892655368"), T(0.7062146892655368), epsilon)); -- 2.54.0 From e673d865fb2dfa6588505d572765ea8c5b4470ee Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 3 Sep 2019 13:02:46 -0400 Subject: [PATCH 16/23] fix stack traces on macos when passing absolute path to root source file The comment added by this commit is copied here: For macOS stack traces, we want to avoid having to parse the compilation unit debug info. As long as each debug info file has a path independent of the compilation unit directory (DW_AT_comp_dir), then we never have to look at the compilation unit debug info. If we provide an absolute path to LLVM here for the compilation unit debug info, LLVM will emit DWARF info that depends on DW_AT_comp_dir. To avoid this, we pass "." for the compilation unit directory. This forces each debug file to have a directory rather than be relative to DW_AT_comp_dir. According to DWARF 5, debug files will no longer reference DW_AT_comp_dir, for the purpose of being able to support the common practice of stripping all but the line number sections from an executable. closes #2700 --- src/codegen.cpp | 15 ++++++++++++++- src/zig_llvm.cpp | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index b694923873a51f8a8f206e282dfecf6558c94f19..293066afd50c54af72c690d0adae0d85b1b33404 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8457,8 +8457,21 @@ static void init(CodeGen *g) { Buf *producer = buf_sprintf("zig %d.%d.%d", ZIG_VERSION_MAJOR, ZIG_VERSION_MINOR, ZIG_VERSION_PATCH); const char *flags = ""; unsigned runtime_version = 0; + + // For macOS stack traces, we want to avoid having to parse the compilation unit debug + // info. As long as each debug info file has a path independent of the compilation unit + // directory (DW_AT_comp_dir), then we never have to look at the compilation unit debug + // info. If we provide an absolute path to LLVM here for the compilation unit debug info, + // LLVM will emit DWARF info that depends on DW_AT_comp_dir. To avoid this, we pass "." + // for the compilation unit directory. This forces each debug file to have a directory + // rather than be relative to DW_AT_comp_dir. According to DWARF 5, debug files will + // no longer reference DW_AT_comp_dir, for the purpose of being able to support the + // common practice of stripping all but the line number sections from an executable. + const char *compile_unit_dir = target_os_is_darwin(g->zig_target->os) ? "." : + buf_ptr(&g->root_package->root_src_dir); + ZigLLVMDIFile *compile_unit_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(g->root_out_name), - buf_ptr(&g->root_package->root_src_dir)); + compile_unit_dir); g->compile_unit = ZigLLVMCreateCompileUnit(g->dbuilder, ZigLLVMLang_DW_LANG_C99(), compile_unit_file, buf_ptr(producer), is_optimized, flags, runtime_version, "", 0, !g->strip_debug_symbols); diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index c19abbbac8f18bb08edc14a02d812240cf5d6812..4f25cd3b98803f9ea8b46fabf978c53008523b14 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -842,6 +842,7 @@ const char *ZigLLVMGetSubArchTypeName(ZigLLVM_SubArchType sub_arch) { void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module) { unwrap(module)->addModuleFlag(Module::Warning, "Debug Info Version", DEBUG_METADATA_VERSION); + unwrap(module)->addModuleFlag(Module::Warning, "Dwarf Version", 4); } void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module) { -- 2.54.0 From be17a4b6c1be11eb4b75db1972a38fc50875ebed Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 3 Sep 2019 14:51:34 -0400 Subject: [PATCH 17/23] fix compiler crash in struct field pointers when the llvm type has not been fully analyzed. This is a regression from lazy values. --- src/codegen.cpp | 7 +++++++ test/stage1/behavior/struct.zig | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/codegen.cpp b/src/codegen.cpp index 293066afd50c54af72c690d0adae0d85b1b33404..1710a3b3fd65c77dc91688aad1d1fa14817d3d1d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4113,6 +4113,8 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStructFieldPtr *instruction) { + Error err; + if (instruction->base.value.special != ConstValSpecialRuntime) return nullptr; @@ -4130,6 +4132,11 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa return struct_ptr; } + ZigType *struct_type = (struct_ptr_type->id == ZigTypeIdPointer) ? + struct_ptr_type->data.pointer.child_type : struct_ptr_type; + if ((err = type_resolve(g, struct_type, ResolveStatusLLVMFull))) + report_errors_and_exit(g); + assert(field->gen_index != SIZE_MAX); return LLVMBuildStructGEP(g->builder, struct_ptr, (unsigned)field->gen_index, ""); } diff --git a/test/stage1/behavior/struct.zig b/test/stage1/behavior/struct.zig index b86b171daf42cf9c3454281178de00a2f0c942e9..0befe4f620d8ddab4dfef9e09780d01e0e7c4ff9 100644 --- a/test/stage1/behavior/struct.zig +++ b/test/stage1/behavior/struct.zig @@ -599,3 +599,36 @@ test "extern fn returns struct by value" { S.entry(); comptime S.entry(); } + +test "for loop over pointers to struct, getting field from struct pointer" { + const S = struct { + const Foo = struct { + name: []const u8, + }; + + var ok = true; + + fn eql(a: []const u8) bool { + return true; + } + + const ArrayList = struct { + fn toSlice(self: *ArrayList) []*Foo { + return ([*]*Foo)(undefined)[0..0]; + } + }; + + fn doTheTest() void { + var objects: ArrayList = undefined; + + for (objects.toSlice()) |obj| { + if (eql(obj.name)) { + ok = false; + } + } + + expect(ok); + } + }; + S.doTheTest(); +} -- 2.54.0 From fc0f8d0359777580c771848361166f97a85deddd Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 3 Sep 2019 16:19:10 -0400 Subject: [PATCH 18/23] zig build: make install prefix available to build.zig and prevent accident of '/' showing up in application/library names --- std/build.zig | 32 ++++++++++++++++++-------------- std/special/build_runner.zig | 2 ++ 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/std/build.zig b/std/build.zig index 27715663f7d936c41dd1516bbda501b6d7d0cced..1ca808c505112982b04563ddf0abc29a4ad2d5f0 100644 --- a/std/build.zig +++ b/std/build.zig @@ -4,6 +4,7 @@ const io = std.io; const fs = std.fs; const mem = std.mem; const debug = std.debug; +const panic = std.debug.panic; const assert = debug.assert; const warn = std.debug.warn; const ArrayList = std.ArrayList; @@ -42,8 +43,8 @@ pub const Builder = struct { top_level_steps: ArrayList(*TopLevelStep), install_prefix: ?[]const u8, dest_dir: ?[]const u8, - lib_dir: ?[]const u8, - exe_dir: ?[]const u8, + lib_dir: []const u8, + exe_dir: []const u8, install_path: []const u8, search_prefixes: ArrayList([]const u8), installed_files: ArrayList(InstalledFile), @@ -129,8 +130,8 @@ pub const Builder = struct { .env_map = env_map, .search_prefixes = ArrayList([]const u8).init(allocator), .install_prefix = null, - .lib_dir = null, - .exe_dir = null, + .lib_dir = undefined, + .exe_dir = undefined, .dest_dir = env_map.get("DESTDIR"), .installed_files = ArrayList(InstalledFile).init(allocator), .install_tls = TopLevelStep{ @@ -163,11 +164,13 @@ pub const Builder = struct { self.allocator.destroy(self); } + /// This function is intended to be called by std/special/build_runner.zig, not a build.zig file. pub fn setInstallPrefix(self: *Builder, optional_prefix: ?[]const u8) void { self.install_prefix = optional_prefix; } - fn resolveInstallPrefix(self: *Builder) void { + /// This function is intended to be called by std/special/build_runner.zig, not a build.zig file. + pub fn resolveInstallPrefix(self: *Builder) void { if (self.dest_dir) |dest_dir| { const install_prefix = self.install_prefix orelse "/usr"; self.install_path = fs.path.join(self.allocator, [_][]const u8{ dest_dir, install_prefix }) catch unreachable; @@ -437,7 +440,7 @@ pub const Builder = struct { .description = description, }; if ((self.available_options_map.put(name, available_option) catch unreachable) != null) { - debug.panic("Option '{}' declared twice", name); + panic("Option '{}' declared twice", name); } self.available_options_list.append(available_option) catch unreachable; @@ -463,8 +466,8 @@ pub const Builder = struct { return null; }, }, - TypeId.Int => debug.panic("TODO integer options to build script"), - TypeId.Float => debug.panic("TODO float options to build script"), + TypeId.Int => panic("TODO integer options to build script"), + TypeId.Float => panic("TODO float options to build script"), TypeId.String => switch (entry.value.value) { UserValue.Flag => { warn("Expected -D{} to be a string, but received a boolean.\n", name); @@ -478,7 +481,7 @@ pub const Builder = struct { }, UserValue.Scalar => |s| return s, }, - TypeId.List => debug.panic("TODO list options to build script"), + TypeId.List => panic("TODO list options to build script"), } } @@ -644,8 +647,6 @@ pub const Builder = struct { } pub fn validateUserInputDidItFail(self: *Builder) bool { - self.resolveInstallPrefix(); - // make sure all args are used var it = self.user_input_options.iterator(); while (true) { @@ -855,7 +856,7 @@ pub const Builder = struct { var stdout_file_in_stream = child.stdout.?.inStream(); try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size); - const term = child.wait() catch |err| std.debug.panic("unable to spawn {}: {}", argv[0], err); + const term = child.wait() catch |err| panic("unable to spawn {}: {}", argv[0], err); switch (term) { .Exited => |code| { if (code != 0) { @@ -882,8 +883,8 @@ pub const Builder = struct { fn getInstallPath(self: *Builder, dir: InstallDir, dest_rel_path: []const u8) []const u8 { const base_dir = switch (dir) { .Prefix => self.install_path, - .Bin => self.exe_dir.?, - .Lib => self.lib_dir.?, + .Bin => self.exe_dir, + .Lib => self.lib_dir, }; return fs.path.resolve( self.allocator, @@ -1318,6 +1319,9 @@ pub const LibExeObjStep = struct { } fn initExtraArgs(builder: *Builder, name: []const u8, root_src: ?[]const u8, kind: Kind, is_dynamic: bool, ver: Version) LibExeObjStep { + if (mem.indexOf(u8, name, "/") != null or mem.indexOf(u8, name, "\\") != null) { + panic("invalid name: '{}'. It looks like a file path, but it is supposed to be the library or application name.", name); + } var self = LibExeObjStep{ .strip = false, .builder = builder, diff --git a/std/special/build_runner.zig b/std/special/build_runner.zig index 4933faca8a22bce38e7f9e1950b64a8acc177c7b..01e307d46e1af16522a1ef0aaf08f51b3336e537 100644 --- a/std/special/build_runner.zig +++ b/std/special/build_runner.zig @@ -123,6 +123,7 @@ pub fn main() !void { } } + builder.resolveInstallPrefix(); try runBuild(builder); if (builder.validateUserInputDidItFail()) @@ -151,6 +152,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void { // run the build script to collect the options if (!already_ran_build) { builder.setInstallPrefix(null); + builder.resolveInstallPrefix(); try runBuild(builder); } -- 2.54.0 From f08c6e4fe6ad63145ef69377f36f34e9f04cadec Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Tue, 3 Sep 2019 23:53:05 +0200 Subject: [PATCH 19/23] changing occurrences of HashMap with []const u8 as keys for StringHashMap --- doc/docgen.zig | 4 ++-- src-self-hosted/arg.zig | 4 ++-- src-self-hosted/compilation.zig | 2 +- src-self-hosted/decl.zig | 2 +- src-self-hosted/main.zig | 2 +- src-self-hosted/package.zig | 2 +- src-self-hosted/stage1.zig | 4 ++-- std/buf_map.zig | 4 ++-- std/buf_set.zig | 4 ++-- std/build.zig | 6 +++--- std/json.zig | 4 ++-- std/mem.zig | 37 +++++++++++---------------------- 12 files changed, 31 insertions(+), 44 deletions(-) diff --git a/doc/docgen.zig b/doc/docgen.zig index 458b97d2c04c3ce49c9b07e11cce21c55fa5ce29..a2b4e8501c93478e8ef19697e79a932b9c801ea3 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -307,7 +307,7 @@ const Node = union(enum) { const Toc = struct { nodes: []Node, toc: []u8, - urls: std.HashMap([]const u8, Token, mem.hash_slice_u8, mem.eql_slice_u8), + urls: std.StringHashMap(Token), }; const Action = enum { @@ -316,7 +316,7 @@ const Action = enum { }; fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc { - var urls = std.HashMap([]const u8, Token, mem.hash_slice_u8, mem.eql_slice_u8).init(allocator); + var urls = std.StringHashMap(Token).init(allocator); errdefer urls.deinit(); var header_stack_size: usize = 0; diff --git a/src-self-hosted/arg.zig b/src-self-hosted/arg.zig index 8f95e2d7ef76a11ac145898f9ad950041cb81778..8b0ea5ea6185ef68adb1d26befda601b2872913c 100644 --- a/src-self-hosted/arg.zig +++ b/src-self-hosted/arg.zig @@ -5,7 +5,7 @@ const mem = std.mem; const Allocator = mem.Allocator; const ArrayList = std.ArrayList; -const HashMap = std.HashMap; +const StringHashMap = std.StringHashMap; fn trimStart(slice: []const u8, ch: u8) []const u8 { var i: usize = 0; @@ -73,7 +73,7 @@ fn readFlagArguments(allocator: *Allocator, args: []const []const u8, required: } } -const HashMapFlags = HashMap([]const u8, FlagArg, std.hash.Fnv1a_32.hash, mem.eql_slice_u8); +const HashMapFlags = StringHashMap(FlagArg); // A store for querying found flags and positional arguments. pub const Args = struct { diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig index a64e52a2b628558e0f3b905c9591ee5017c52a49..1e71a5e561a88fd2f9b7564b597b956a14120ae8 100644 --- a/src-self-hosted/compilation.zig +++ b/src-self-hosted/compilation.zig @@ -249,7 +249,7 @@ pub const Compilation = struct { const ArrayTypeTable = std.HashMap(*const Type.Array.Key, *Type.Array, Type.Array.Key.hash, Type.Array.Key.eql); const PtrTypeTable = std.HashMap(*const Type.Pointer.Key, *Type.Pointer, Type.Pointer.Key.hash, Type.Pointer.Key.eql); const FnTypeTable = std.HashMap(*const Type.Fn.Key, *Type.Fn, Type.Fn.Key.hash, Type.Fn.Key.eql); - const TypeTable = std.HashMap([]const u8, *Type, mem.hash_slice_u8, mem.eql_slice_u8); + const TypeTable = std.StringHashMap(*Type); const CompileErrList = std.ArrayList(*Msg); diff --git a/src-self-hosted/decl.zig b/src-self-hosted/decl.zig index 25fcf195d1adbc738a756957d23ebe3d961ec660..1af06dea3988d336e05918aa626a12d2acb9c626 100644 --- a/src-self-hosted/decl.zig +++ b/src-self-hosted/decl.zig @@ -20,7 +20,7 @@ pub const Decl = struct { // TODO when we destroy the decl, deref the tree scope tree_scope: *Scope.AstTree, - pub const Table = std.HashMap([]const u8, *Decl, mem.hash_slice_u8, mem.eql_slice_u8); + pub const Table = std.StringHashMap(*Decl); pub fn cast(base: *Decl, comptime T: type) ?*T { if (base.id != @field(Id, @typeName(T))) return null; diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig index 5136b32735020dbdec0475aeeb0230e8082754a1..52eda5824aef40a55f2e8f926071eb3a43d36f7d 100644 --- a/src-self-hosted/main.zig +++ b/src-self-hosted/main.zig @@ -541,7 +541,7 @@ const Fmt = struct { color: errmsg.Color, loop: *event.Loop, - const SeenMap = std.HashMap([]const u8, void, mem.hash_slice_u8, mem.eql_slice_u8); + const SeenMap = std.StringHashMap(void); }; fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_file: []const u8) void { diff --git a/src-self-hosted/package.zig b/src-self-hosted/package.zig index 0d31731b551e6dd730aaf379c989dc3a8f098244..c8d46c771976f4d86ba663c9faa441ea12e4399d 100644 --- a/src-self-hosted/package.zig +++ b/src-self-hosted/package.zig @@ -10,7 +10,7 @@ pub const Package = struct { /// relative to root_src_dir table: Table, - pub const Table = std.HashMap([]const u8, *Package, mem.hash_slice_u8, mem.eql_slice_u8); + pub const Table = std.StringHashMap(*Package); /// makes internal copies of root_src_dir and root_src_path /// allocator should be an arena allocator because Package never frees anything diff --git a/src-self-hosted/stage1.zig b/src-self-hosted/stage1.zig index b8f13b5d03746eacb88e31a5a9bbadb8297084cc..2f48f2f45076e4ad3d844689c2a09e97826ea974 100644 --- a/src-self-hosted/stage1.zig +++ b/src-self-hosted/stage1.zig @@ -343,7 +343,7 @@ const Fmt = struct { color: errmsg.Color, allocator: *mem.Allocator, - const SeenMap = std.HashMap([]const u8, void, mem.hash_slice_u8, mem.eql_slice_u8); + const SeenMap = std.StringHashMap(void); }; fn printErrMsgToFile( @@ -376,7 +376,7 @@ fn printErrMsgToFile( const text = text_buf.toOwnedSlice(); const stream = &file.outStream().stream; - try stream.print( "{}:{}:{}: error: {}\n", path, start_loc.line + 1, start_loc.column + 1, text); + try stream.print("{}:{}:{}: error: {}\n", path, start_loc.line + 1, start_loc.column + 1, text); if (!color_on) return; diff --git a/std/buf_map.zig b/std/buf_map.zig index 4079d41caf1c94fea99ab75b5158a583ccdf6230..d7aa314157b4aa895bef516c874d9de7c4ed1996 100644 --- a/std/buf_map.zig +++ b/std/buf_map.zig @@ -1,5 +1,5 @@ const std = @import("std.zig"); -const HashMap = std.HashMap; +const StringHashMap = std.StringHashMap; const mem = std.mem; const Allocator = mem.Allocator; const testing = std.testing; @@ -9,7 +9,7 @@ const testing = std.testing; pub const BufMap = struct { hash_map: BufMapHashMap, - const BufMapHashMap = HashMap([]const u8, []const u8, mem.hash_slice_u8, mem.eql_slice_u8); + const BufMapHashMap = StringHashMap([]const u8); pub fn init(allocator: *Allocator) BufMap { var self = BufMap{ .hash_map = BufMapHashMap.init(allocator) }; diff --git a/std/buf_set.zig b/std/buf_set.zig index 33e66a64e86b3f95d08732dbc5e15c8678d02bb4..1a321e89c9eb6ca8ff2ac5b4fa7c176059d46cb4 100644 --- a/std/buf_set.zig +++ b/std/buf_set.zig @@ -1,5 +1,5 @@ const std = @import("std.zig"); -const HashMap = @import("hash_map.zig").HashMap; +const StringHashMap = std.StringHashMap; const mem = @import("mem.zig"); const Allocator = mem.Allocator; const testing = std.testing; @@ -7,7 +7,7 @@ const testing = std.testing; pub const BufSet = struct { hash_map: BufSetHashMap, - const BufSetHashMap = HashMap([]const u8, void, mem.hash_slice_u8, mem.eql_slice_u8); + const BufSetHashMap = StringHashMap(void); pub fn init(a: *Allocator) BufSet { var self = BufSet{ .hash_map = BufSetHashMap.init(a) }; diff --git a/std/build.zig b/std/build.zig index 27715663f7d936c41dd1516bbda501b6d7d0cced..0049dcd035b1931f1bc01429f7b5956c4f838852 100644 --- a/std/build.zig +++ b/std/build.zig @@ -7,7 +7,7 @@ const debug = std.debug; const assert = debug.assert; const warn = std.debug.warn; const ArrayList = std.ArrayList; -const HashMap = std.HashMap; +const StringHashMap = std.StringHashMap; const Allocator = mem.Allocator; const process = std.process; const BufSet = std.BufSet; @@ -60,8 +60,8 @@ pub const Builder = struct { C11, }; - const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8); - const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8); + const UserInputOptionsMap = StringHashMap(UserInputOption); + const AvailableOptionsMap = StringHashMap(AvailableOption); const AvailableOption = struct { name: []const u8, diff --git a/std/json.zig b/std/json.zig index 8324c59e32657f0c8e4c5c0ad0b3f2c5966a3d71..f562a672f86d5bdfbe35ab7930903ecdef7d236c 100644 --- a/std/json.zig +++ b/std/json.zig @@ -989,7 +989,7 @@ test "json.validate" { const Allocator = std.mem.Allocator; const ArenaAllocator = std.heap.ArenaAllocator; const ArrayList = std.ArrayList; -const HashMap = std.HashMap; +const StringHashMap = std.StringHashMap; pub const ValueTree = struct { arena: ArenaAllocator, @@ -1000,7 +1000,7 @@ pub const ValueTree = struct { } }; -pub const ObjectMap = HashMap([]const u8, Value, mem.hash_slice_u8, mem.eql_slice_u8); +pub const ObjectMap = StringHashMap(Value); pub const Value = union(enum) { Null, diff --git a/std/mem.zig b/std/mem.zig index 61dc5c7a30e3b1ed7955ce0efced5dc411ae6f9e..62a1ae886af184c9005211914c37f17f02270df4 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -738,47 +738,34 @@ test "writeIntBig and writeIntLittle" { var buf9: [9]u8 = undefined; writeIntBig(u0, &buf0, 0x0); - testing.expect(eql_slice_u8(buf0[0..], [_]u8{})); + testing.expect(eql(u8, buf0[0..], [_]u8{})); writeIntLittle(u0, &buf0, 0x0); - testing.expect(eql_slice_u8(buf0[0..], [_]u8{})); + testing.expect(eql(u8, buf0[0..], [_]u8{})); writeIntBig(u8, &buf1, 0x12); - testing.expect(eql_slice_u8(buf1[0..], [_]u8{0x12})); + testing.expect(eql(u8, buf1[0..], [_]u8{0x12})); writeIntLittle(u8, &buf1, 0x34); - testing.expect(eql_slice_u8(buf1[0..], [_]u8{0x34})); + testing.expect(eql(u8, buf1[0..], [_]u8{0x34})); writeIntBig(u16, &buf2, 0x1234); - testing.expect(eql_slice_u8(buf2[0..], [_]u8{ 0x12, 0x34 })); + testing.expect(eql(u8, buf2[0..], [_]u8{ 0x12, 0x34 })); writeIntLittle(u16, &buf2, 0x5678); - testing.expect(eql_slice_u8(buf2[0..], [_]u8{ 0x78, 0x56 })); + testing.expect(eql(u8, buf2[0..], [_]u8{ 0x78, 0x56 })); writeIntBig(u72, &buf9, 0x123456789abcdef024); - testing.expect(eql_slice_u8(buf9[0..], [_]u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 })); + testing.expect(eql(u8, buf9[0..], [_]u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 })); writeIntLittle(u72, &buf9, 0xfedcba9876543210ec); - testing.expect(eql_slice_u8(buf9[0..], [_]u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe })); + testing.expect(eql(u8, buf9[0..], [_]u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe })); writeIntBig(i8, &buf1, -1); - testing.expect(eql_slice_u8(buf1[0..], [_]u8{0xff})); + testing.expect(eql(u8, buf1[0..], [_]u8{0xff})); writeIntLittle(i8, &buf1, -2); - testing.expect(eql_slice_u8(buf1[0..], [_]u8{0xfe})); + testing.expect(eql(u8, buf1[0..], [_]u8{0xfe})); writeIntBig(i16, &buf2, -3); - testing.expect(eql_slice_u8(buf2[0..], [_]u8{ 0xff, 0xfd })); + testing.expect(eql(u8, buf2[0..], [_]u8{ 0xff, 0xfd })); writeIntLittle(i16, &buf2, -4); - testing.expect(eql_slice_u8(buf2[0..], [_]u8{ 0xfc, 0xff })); -} - -pub fn hash_slice_u8(k: []const u8) u32 { - // FNV 32-bit hash - var h: u32 = 2166136261; - for (k) |b| { - h = (h ^ b) *% 16777619; - } - return h; -} - -pub fn eql_slice_u8(a: []const u8, b: []const u8) bool { - return eql(u8, a, b); + testing.expect(eql(u8, buf2[0..], [_]u8{ 0xfc, 0xff })); } /// Returns an iterator that iterates over the slices of `buffer` that are not -- 2.54.0 From 9d6f236728cf433b44048e21f81efdd167fe0098 Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Tue, 3 Sep 2019 23:56:04 +0200 Subject: [PATCH 20/23] add fastpath for std.mem.eql and simplify std.hash_map.eqlString this should also be friendlier to the optimizer --- std/hash_map.zig | 4 +--- std/mem.zig | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/std/hash_map.zig b/std/hash_map.zig index 5a852d4302f218b13403c4f7cd011c45727e7d43..4ffe88067b582149010c13df696525824decb43f 100644 --- a/std/hash_map.zig +++ b/std/hash_map.zig @@ -23,9 +23,7 @@ pub fn StringHashMap(comptime V: type) type { } pub fn eqlString(a: []const u8, b: []const u8) bool { - if (a.len != b.len) return false; - if (a.ptr == b.ptr) return true; - return mem.compare(u8, a, b) == .Equal; + return mem.eql(u8, a, b); } pub fn hashString(s: []const u8) u32 { diff --git a/std/mem.zig b/std/mem.zig index 62a1ae886af184c9005211914c37f17f02270df4..2091eb4804f7e7d30c689e6cea495aebdba6d1e5 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -339,6 +339,7 @@ test "mem.lessThan" { /// Compares two slices and returns whether they are equal. pub fn eql(comptime T: type, a: []const T, b: []const T) bool { if (a.len != b.len) return false; + if (a.ptr == b.ptr) return true; for (a) |item, index| { if (b[index] != item) return false; } -- 2.54.0 From 18620756520d198f581b9a9acbf25c8cbb79ad11 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 3 Sep 2019 18:25:00 -0400 Subject: [PATCH 21/23] fix union field ptr ir instruction --- src/ir.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index e3b440d0f5c3a55630be16513467887ca005032b..abf4f477a8c3afb30ba774b292eb04d53dfb4640 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -17464,7 +17464,12 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ return ir_analyze_container_member_access_inner(ira, bare_type, field_name, source_instr, container_ptr, container_type); } - ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field->type_entry, + + ZigType *field_type = resolve_union_field_type(ira->codegen, field); + if (field_type == nullptr) + return ira->codegen->invalid_instruction; + + ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field_type, is_const, is_volatile, PtrLenSingle, 0, 0, 0, false); if (instr_is_comptime(container_ptr)) { ConstExprValue *ptr_val = ir_resolve_const(ira, container_ptr, UndefBad); @@ -17481,7 +17486,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ if (initializing) { ConstExprValue *payload_val = create_const_vals(1); payload_val->special = ConstValSpecialUndef; - payload_val->type = field->type_entry; + payload_val->type = field_type; payload_val->parent.id = ConstParentIdUnion; payload_val->parent.data.p_union.union_val = union_val; -- 2.54.0 From ce14c543d165efbd926ea6bd654d999c625b366f Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Tue, 3 Sep 2019 22:29:04 +0200 Subject: [PATCH 22/23] error message and test for alignment of variables of zero-bit types --- src/analyze.cpp | 4 ++++ src/ir.cpp | 6 ++++++ test/compile_errors.zig | 9 +++++++++ 3 files changed, 19 insertions(+) diff --git a/src/analyze.cpp b/src/analyze.cpp index 188da185150bfe70ad510a150d337dca29d1e6cd..2fd540a64f850441d5ecb7d5dd11625729079add 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2671,6 +2671,10 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { } } + if (!type_has_bits(struct_type)) { + assert(struct_type->abi_align == 0); + } + struct_type->data.structure.resolve_loop_flag_other = false; if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) { diff --git a/src/ir.cpp b/src/ir.cpp index abf4f477a8c3afb30ba774b292eb04d53dfb4640..7415a2dd6b182603ad03a71ced0040373fce1a20 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -14839,6 +14839,12 @@ static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_in if (align != 0) { if ((err = type_resolve(ira->codegen, var_type, ResolveStatusAlignmentKnown))) return ira->codegen->invalid_instruction; + if (!type_has_bits(var_type)) { + ir_add_error(ira, source_inst, + buf_sprintf("variable '%s' of zero-bit type '%s' has no in-memory representation, it cannot be aligned", + name_hint, buf_ptr(&var_type->name))); + return ira->codegen->invalid_instruction; + } } assert(result->base.value.data.x_ptr.special != ConstPtrSpecialInvalid); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 12f17ec790e9fe06a1d3e1fb4c0edfcee6a570f9..871ff63e2365870c70696fdac4ce9d13405496aa 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -6462,4 +6462,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:5:30: error: expression value is ignored", "tmp.zig:9:30: error: expression value is ignored", ); + + cases.add( + "aligned variable of zero-bit type", + \\export fn f() void { + \\ var s: struct {} align(4) = undefined; + \\} + , + "tmp.zig:2:5: error: variable 's' of zero-bit type 'struct:2:12' has no in-memory representation, it cannot be aligned", + ); } -- 2.54.0 From 77a5f888be664f9ef09e2c93f52338448e992e00 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 3 Sep 2019 22:09:47 -0400 Subject: [PATCH 23/23] emit a compile error if a test becomes async See #3117 --- src/analyze.cpp | 2 +- src/analyze.hpp | 2 ++ src/codegen.cpp | 10 ++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 2fd540a64f850441d5ecb7d5dd11625729079add..e1d6b59ddf0b5e10c109c45e1e34225e3d01c4ba 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -4195,7 +4195,7 @@ bool fn_is_async(ZigFn *fn) { return fn->inferred_async_node != inferred_async_none; } -static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) { +void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) { assert(fn->inferred_async_node != nullptr); assert(fn->inferred_async_node != inferred_async_checking); assert(fn->inferred_async_node != inferred_async_none); diff --git a/src/analyze.hpp b/src/analyze.hpp index dc702167e7c4d852bde710deb472fd35cd44c30b..9f2c984992908574c9726b99a7c8ec355a9385dc 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -256,4 +256,6 @@ Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, ZigType * ZigType *resolve_union_field_type(CodeGen *g, TypeUnionField *union_field); ZigType *resolve_struct_field_type(CodeGen *g, TypeStructField *struct_field); +void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn); + #endif diff --git a/src/codegen.cpp b/src/codegen.cpp index 1710a3b3fd65c77dc91688aad1d1fa14817d3d1d..d1499592d2f9264c9fb1e348978caf6c0763ec11 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8905,6 +8905,15 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) { for (size_t i = 0; i < g->test_fns.length; i += 1) { ZigFn *test_fn_entry = g->test_fns.at(i); + if (fn_is_async(test_fn_entry)) { + ErrorMsg *msg = add_node_error(g, test_fn_entry->proto_node, + buf_create_from_str("test functions cannot be async")); + add_error_note(g, msg, test_fn_entry->proto_node, + buf_sprintf("this restriction may be lifted in the future. See https://github.com/ziglang/zig/issues/3117 for more details")); + add_async_error_notes(g, msg, test_fn_entry); + continue; + } + ConstExprValue *this_val = &test_fn_array->data.x_array.data.s_none.elements[i]; this_val->special = ConstValSpecialStatic; this_val->type = struct_type; @@ -8924,6 +8933,7 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) { fn_field->data.x_ptr.mut = ConstPtrMutComptimeConst; fn_field->data.x_ptr.data.fn.fn_entry = test_fn_entry; } + report_errors_and_maybe_exit(g); ConstExprValue *test_fn_slice = create_const_slice(g, test_fn_array, 0, g->test_fns.length, true); -- 2.54.0