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 281f09d57b..dc3e6190f5 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 ef5c8f2346..b66cbeb860 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) { 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 dc3e6190f5..3150c5babd 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 b66cbeb860..8270577d7a 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); 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 876d84e173..404c82e9b8 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" { 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 35c598ab97..fa239808f5 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 7d6a8154ea..3df8aef3b0 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(); +} 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 f7152971a4..23ec3e53ce 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 0000000000..267c3a131a --- /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); +} 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 d9e1dc44ca..708db8848d 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 890724d950..74de8634cc 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 8a1f889234..5519f98fd2 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 c0945ef180..6f1ccd418c 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 9393d72c15..27715663f7 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; 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 e1c7bb37fe..3727e87915 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 005a790f5f..605a725e4b 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); +} 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 3727e87915..01066e51c3 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 605a725e4b..ad8e949f8b 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); +} 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 74de8634cc..0b51df1e82 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 5f92962957..70712ea85a 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"); +} 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 beb4ac671c..f296f9dee4 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}") 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 708db8848d..1a97cf2814 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 0b51df1e82..b694923873 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 01066e51c3..e3b440d0f5 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; 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 45758d4075..cc0405c21a 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 0000000000..3c71b9626a --- /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 f7ef05d3cd..1bb9e417e5 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, 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 cc0405c21a..f8c095e825 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 3c71b9626a..3de0fb680a 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 1bb9e417e5..754407df9a 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| { 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 f8c095e825..21fa79e863 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 3de0fb680a..1a014f07cc 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 754407df9a..99ee5949c3 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, 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 ce2cc70768..d0a826a55e 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)); 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 b694923873..293066afd5 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 c19abbbac8..4f25cd3b98 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) { 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 293066afd5..1710a3b3fd 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 b86b171daf..0befe4f620 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(); +} 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 27715663f7..1ca808c505 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 4933faca8a..01e307d46e 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); } 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 458b97d2c0..a2b4e8501c 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 8f95e2d7ef..8b0ea5ea61 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 a64e52a2b6..1e71a5e561 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 25fcf195d1..1af06dea39 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 5136b32735..52eda5824a 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 0d31731b55..c8d46c7719 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 b8f13b5d03..2f48f2f450 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 4079d41caf..d7aa314157 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 33e66a64e8..1a321e89c9 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 27715663f7..0049dcd035 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 8324c59e32..f562a672f8 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 61dc5c7a30..62a1ae886a 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 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 5a852d4302..4ffe88067b 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 62a1ae886a..2091eb4804 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; } 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 e3b440d0f5..abf4f477a8 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; 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 188da18515..2fd540a64f 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 abf4f477a8..7415a2dd6b 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 12f17ec790..871ff63e23 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", + ); } 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 2fd540a64f..e1d6b59ddf 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 dc702167e7..9f2c984992 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 1710a3b3fd..d1499592d2 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);