| author | |
| committer | |
| log | 5308eb7045b7b6a48356c6e814baf2a45a094d80 |
| tree | 88b2bd51d15a72b1aa27c51fdc54a2c51d8c827a |
| parent | d62f7c6b605a672f032aff8870496d2ae2366017 |
| parent | 77a5f888be664f9ef09e2c93f52338448e992e00 |
36 files changed, 964 insertions(+), 124 deletions(-)
CMakeLists.txt+10-6| ... | ... | @@ -23,14 +23,18 @@ find_program(GIT_EXE NAMES git) |
| 23 | 23 | if(GIT_EXE) |
| 24 | 24 | execute_process( |
| 25 | 25 | COMMAND ${GIT_EXE} -C ${CMAKE_SOURCE_DIR} name-rev HEAD --tags --name-only --no-undefined --always |
| 26 | RESULT_VARIABLE EXIT_STATUS | |
| 26 | 27 | OUTPUT_VARIABLE ZIG_GIT_REV |
| 27 | OUTPUT_STRIP_TRAILING_WHITESPACE) | |
| 28 | if(ZIG_GIT_REV MATCHES "\\^0$") | |
| 29 | if(NOT("${ZIG_GIT_REV}" STREQUAL "${ZIG_VERSION}^0")) | |
| 30 | message("WARNING: Tag does not match configured Zig version") | |
| 28 | OUTPUT_STRIP_TRAILING_WHITESPACE | |
| 29 | ERROR_QUIET) | |
| 30 | if(EXIT_STATUS EQUAL "0") | |
| 31 | if(ZIG_GIT_REV MATCHES "\\^0$") | |
| 32 | if(NOT("${ZIG_GIT_REV}" STREQUAL "${ZIG_VERSION}^0")) | |
| 33 | message("WARNING: Tag does not match configured Zig version") | |
| 34 | endif() | |
| 35 | else() | |
| 36 | set(ZIG_VERSION "${ZIG_VERSION}+${ZIG_GIT_REV}") | |
| 31 | 37 | endif() |
| 32 | else() | |
| 33 | set(ZIG_VERSION "${ZIG_VERSION}+${ZIG_GIT_REV}") | |
| 34 | 38 | endif() |
| 35 | 39 | endif() |
| 36 | 40 | message("Configuring zig version ${ZIG_VERSION}") |
build.zig+2-1| ... | ... | @@ -138,12 +138,13 @@ pub fn build(b: *Builder) !void { |
| 138 | 138 | |
| 139 | 139 | test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes)); |
| 140 | 140 | test_step.dependOn(tests.addStandaloneTests(b, test_filter, modes)); |
| 141 | test_step.dependOn(tests.addStackTraceTests(b, test_filter, modes)); | |
| 141 | 142 | test_step.dependOn(tests.addCliTests(b, test_filter, modes)); |
| 142 | test_step.dependOn(tests.addCompileErrorTests(b, test_filter, modes)); | |
| 143 | 143 | test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes)); |
| 144 | 144 | test_step.dependOn(tests.addRuntimeSafetyTests(b, test_filter, modes)); |
| 145 | 145 | test_step.dependOn(tests.addTranslateCTests(b, test_filter)); |
| 146 | 146 | test_step.dependOn(tests.addGenHTests(b, test_filter)); |
| 147 | test_step.dependOn(tests.addCompileErrorTests(b, test_filter, modes)); | |
| 147 | 148 | test_step.dependOn(docs_step); |
| 148 | 149 | } |
| 149 | 150 |
doc/docgen.zig+2-2| ... | ... | @@ -307,7 +307,7 @@ const Node = union(enum) { |
| 307 | 307 | const Toc = struct { |
| 308 | 308 | nodes: []Node, |
| 309 | 309 | toc: []u8, |
| 310 | urls: std.HashMap([]const u8, Token, mem.hash_slice_u8, mem.eql_slice_u8), | |
| 310 | urls: std.StringHashMap(Token), | |
| 311 | 311 | }; |
| 312 | 312 | |
| 313 | 313 | const Action = enum { |
| ... | ... | @@ -316,7 +316,7 @@ const Action = enum { |
| 316 | 316 | }; |
| 317 | 317 | |
| 318 | 318 | fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc { |
| 319 | var urls = std.HashMap([]const u8, Token, mem.hash_slice_u8, mem.eql_slice_u8).init(allocator); | |
| 319 | var urls = std.StringHashMap(Token).init(allocator); | |
| 320 | 320 | errdefer urls.deinit(); |
| 321 | 321 | |
| 322 | 322 | var header_stack_size: usize = 0; |
src-self-hosted/arg.zig+2-2| ... | ... | @@ -5,7 +5,7 @@ const mem = std.mem; |
| 5 | 5 | |
| 6 | 6 | const Allocator = mem.Allocator; |
| 7 | 7 | const ArrayList = std.ArrayList; |
| 8 | const HashMap = std.HashMap; | |
| 8 | const StringHashMap = std.StringHashMap; | |
| 9 | 9 | |
| 10 | 10 | fn trimStart(slice: []const u8, ch: u8) []const u8 { |
| 11 | 11 | var i: usize = 0; |
| ... | ... | @@ -73,7 +73,7 @@ fn readFlagArguments(allocator: *Allocator, args: []const []const u8, required: |
| 73 | 73 | } |
| 74 | 74 | } |
| 75 | 75 | |
| 76 | const HashMapFlags = HashMap([]const u8, FlagArg, std.hash.Fnv1a_32.hash, mem.eql_slice_u8); | |
| 76 | const HashMapFlags = StringHashMap(FlagArg); | |
| 77 | 77 | |
| 78 | 78 | // A store for querying found flags and positional arguments. |
| 79 | 79 | pub const Args = struct { |
src-self-hosted/compilation.zig+1-1| ... | ... | @@ -249,7 +249,7 @@ pub const Compilation = struct { |
| 249 | 249 | const ArrayTypeTable = std.HashMap(*const Type.Array.Key, *Type.Array, Type.Array.Key.hash, Type.Array.Key.eql); |
| 250 | 250 | const PtrTypeTable = std.HashMap(*const Type.Pointer.Key, *Type.Pointer, Type.Pointer.Key.hash, Type.Pointer.Key.eql); |
| 251 | 251 | const FnTypeTable = std.HashMap(*const Type.Fn.Key, *Type.Fn, Type.Fn.Key.hash, Type.Fn.Key.eql); |
| 252 | const TypeTable = std.HashMap([]const u8, *Type, mem.hash_slice_u8, mem.eql_slice_u8); | |
| 252 | const TypeTable = std.StringHashMap(*Type); | |
| 253 | 253 | |
| 254 | 254 | const CompileErrList = std.ArrayList(*Msg); |
| 255 | 255 |
src-self-hosted/decl.zig+1-1| ... | ... | @@ -20,7 +20,7 @@ pub const Decl = struct { |
| 20 | 20 | // TODO when we destroy the decl, deref the tree scope |
| 21 | 21 | tree_scope: *Scope.AstTree, |
| 22 | 22 | |
| 23 | pub const Table = std.HashMap([]const u8, *Decl, mem.hash_slice_u8, mem.eql_slice_u8); | |
| 23 | pub const Table = std.StringHashMap(*Decl); | |
| 24 | 24 | |
| 25 | 25 | pub fn cast(base: *Decl, comptime T: type) ?*T { |
| 26 | 26 | if (base.id != @field(Id, @typeName(T))) return null; |
src-self-hosted/main.zig+1-1| ... | ... | @@ -541,7 +541,7 @@ const Fmt = struct { |
| 541 | 541 | color: errmsg.Color, |
| 542 | 542 | loop: *event.Loop, |
| 543 | 543 | |
| 544 | const SeenMap = std.HashMap([]const u8, void, mem.hash_slice_u8, mem.eql_slice_u8); | |
| 544 | const SeenMap = std.StringHashMap(void); | |
| 545 | 545 | }; |
| 546 | 546 | |
| 547 | 547 | fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_file: []const u8) void { |
src-self-hosted/package.zig+1-1| ... | ... | @@ -10,7 +10,7 @@ pub const Package = struct { |
| 10 | 10 | /// relative to root_src_dir |
| 11 | 11 | table: Table, |
| 12 | 12 | |
| 13 | pub const Table = std.HashMap([]const u8, *Package, mem.hash_slice_u8, mem.eql_slice_u8); | |
| 13 | pub const Table = std.StringHashMap(*Package); | |
| 14 | 14 | |
| 15 | 15 | /// makes internal copies of root_src_dir and root_src_path |
| 16 | 16 | /// allocator should be an arena allocator because Package never frees anything |
src-self-hosted/stage1.zig+2-2| ... | ... | @@ -343,7 +343,7 @@ const Fmt = struct { |
| 343 | 343 | color: errmsg.Color, |
| 344 | 344 | allocator: *mem.Allocator, |
| 345 | 345 | |
| 346 | const SeenMap = std.HashMap([]const u8, void, mem.hash_slice_u8, mem.eql_slice_u8); | |
| 346 | const SeenMap = std.StringHashMap(void); | |
| 347 | 347 | }; |
| 348 | 348 | |
| 349 | 349 | fn printErrMsgToFile( |
| ... | ... | @@ -376,7 +376,7 @@ fn printErrMsgToFile( |
| 376 | 376 | const text = text_buf.toOwnedSlice(); |
| 377 | 377 | |
| 378 | 378 | const stream = &file.outStream().stream; |
| 379 | try stream.print( "{}:{}:{}: error: {}\n", path, start_loc.line + 1, start_loc.column + 1, text); | |
| 379 | try stream.print("{}:{}:{}: error: {}\n", path, start_loc.line + 1, start_loc.column + 1, text); | |
| 380 | 380 | |
| 381 | 381 | if (!color_on) return; |
| 382 | 382 |
src/all_types.hpp+2| ... | ... | @@ -1989,6 +1989,7 @@ struct CodeGen { |
| 1989 | 1989 | bool system_linker_hack; |
| 1990 | 1990 | bool reported_bad_link_libc_error; |
| 1991 | 1991 | bool is_dynamic; // shared library rather than static library. dynamic musl rather than static musl. |
| 1992 | bool need_frame_size_prefix_data; | |
| 1992 | 1993 | |
| 1993 | 1994 | //////////////////////////// Participates in Input Parameter Cache Hash |
| 1994 | 1995 | /////// Note: there is a separate cache hash for builtin.zig, when adding fields, |
| ... | ... | @@ -2003,6 +2004,7 @@ struct CodeGen { |
| 2003 | 2004 | ZigList<Buf *> assembly_files; |
| 2004 | 2005 | ZigList<CFile *> c_source_files; |
| 2005 | 2006 | ZigList<const char *> lib_dirs; |
| 2007 | ZigList<const char *> framework_dirs; | |
| 2006 | 2008 | |
| 2007 | 2009 | ZigLibCInstallation *libc; |
| 2008 | 2010 |
src/analyze.cpp+12-3| ... | ... | @@ -2671,6 +2671,10 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { |
| 2671 | 2671 | } |
| 2672 | 2672 | } |
| 2673 | 2673 | |
| 2674 | if (!type_has_bits(struct_type)) { | |
| 2675 | assert(struct_type->abi_align == 0); | |
| 2676 | } | |
| 2677 | ||
| 2674 | 2678 | struct_type->data.structure.resolve_loop_flag_other = false; |
| 2675 | 2679 | |
| 2676 | 2680 | if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) { |
| ... | ... | @@ -4191,7 +4195,7 @@ bool fn_is_async(ZigFn *fn) { |
| 4191 | 4195 | return fn->inferred_async_node != inferred_async_none; |
| 4192 | 4196 | } |
| 4193 | 4197 | |
| 4194 | static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) { | |
| 4198 | void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) { | |
| 4195 | 4199 | assert(fn->inferred_async_node != nullptr); |
| 4196 | 4200 | assert(fn->inferred_async_node != inferred_async_checking); |
| 4197 | 4201 | assert(fn->inferred_async_node != inferred_async_none); |
| ... | ... | @@ -7687,8 +7691,13 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta |
| 7687 | 7691 | ZigType *tag_type = union_type->data.unionation.tag_type; |
| 7688 | 7692 | uint32_t gen_field_count = union_type->data.unionation.gen_field_count; |
| 7689 | 7693 | if (gen_field_count == 0) { |
| 7690 | union_type->llvm_type = get_llvm_type(g, tag_type); | |
| 7691 | union_type->llvm_di_type = get_llvm_di_type(g, tag_type); | |
| 7694 | if (tag_type == nullptr) { | |
| 7695 | union_type->llvm_type = g->builtin_types.entry_void->llvm_type; | |
| 7696 | union_type->llvm_di_type = g->builtin_types.entry_void->llvm_di_type; | |
| 7697 | } else { | |
| 7698 | union_type->llvm_type = get_llvm_type(g, tag_type); | |
| 7699 | union_type->llvm_di_type = get_llvm_di_type(g, tag_type); | |
| 7700 | } | |
| 7692 | 7701 | union_type->data.unionation.resolve_status = ResolveStatusLLVMFull; |
| 7693 | 7702 | return; |
| 7694 | 7703 | } |
src/analyze.hpp+2| ... | ... | @@ -256,4 +256,6 @@ Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, ZigType * |
| 256 | 256 | ZigType *resolve_union_field_type(CodeGen *g, TypeUnionField *union_field); |
| 257 | 257 | ZigType *resolve_struct_field_type(CodeGen *g, TypeStructField *struct_field); |
| 258 | 258 | |
| 259 | void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn); | |
| 260 | ||
| 259 | 261 | #endif |
src/codegen.cpp+45-2| ... | ... | @@ -3522,6 +3522,15 @@ static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, Ir |
| 3522 | 3522 | assert(ptr_type->id == ZigTypeIdPointer); |
| 3523 | 3523 | if (!type_has_bits(ptr_type)) |
| 3524 | 3524 | return nullptr; |
| 3525 | if (instruction->ptr->ref_count == 0) { | |
| 3526 | // In this case, this StorePtr instruction should be elided. Something happened like this: | |
| 3527 | // var t = true; | |
| 3528 | // const x = if (t) Num.Two else unreachable; | |
| 3529 | // The if condition is a runtime value, so the StorePtr for `x = Num.Two` got generated | |
| 3530 | // (this instruction being rendered) but because of `else unreachable` the result ended | |
| 3531 | // up being a comptime const value. | |
| 3532 | return nullptr; | |
| 3533 | } | |
| 3525 | 3534 | |
| 3526 | 3535 | bool have_init_expr = !value_is_all_undef(&instruction->value->value); |
| 3527 | 3536 | if (have_init_expr) { |
| ... | ... | @@ -3766,6 +3775,7 @@ static void render_async_var_decls(CodeGen *g, Scope *scope) { |
| 3766 | 3775 | } |
| 3767 | 3776 | |
| 3768 | 3777 | static LLVMValueRef gen_frame_size(CodeGen *g, LLVMValueRef fn_val) { |
| 3778 | assert(g->need_frame_size_prefix_data); | |
| 3769 | 3779 | LLVMTypeRef usize_llvm_type = g->builtin_types.entry_usize->llvm_type; |
| 3770 | 3780 | LLVMTypeRef ptr_usize_llvm_type = LLVMPointerType(usize_llvm_type, 0); |
| 3771 | 3781 | LLVMValueRef casted_fn_val = LLVMBuildBitCast(g->builder, fn_val, ptr_usize_llvm_type, ""); |
| ... | ... | @@ -4103,6 +4113,8 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 4103 | 4113 | static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executable, |
| 4104 | 4114 | IrInstructionStructFieldPtr *instruction) |
| 4105 | 4115 | { |
| 4116 | Error err; | |
| 4117 | ||
| 4106 | 4118 | if (instruction->base.value.special != ConstValSpecialRuntime) |
| 4107 | 4119 | return nullptr; |
| 4108 | 4120 | |
| ... | ... | @@ -4120,6 +4132,11 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa |
| 4120 | 4132 | return struct_ptr; |
| 4121 | 4133 | } |
| 4122 | 4134 | |
| 4135 | ZigType *struct_type = (struct_ptr_type->id == ZigTypeIdPointer) ? | |
| 4136 | struct_ptr_type->data.pointer.child_type : struct_ptr_type; | |
| 4137 | if ((err = type_resolve(g, struct_type, ResolveStatusLLVMFull))) | |
| 4138 | report_errors_and_exit(g); | |
| 4139 | ||
| 4123 | 4140 | assert(field->gen_index != SIZE_MAX); |
| 4124 | 4141 | return LLVMBuildStructGEP(g->builder, struct_ptr, (unsigned)field->gen_index, ""); |
| 4125 | 4142 | } |
| ... | ... | @@ -7199,7 +7216,9 @@ static void do_code_gen(CodeGen *g) { |
| 7199 | 7216 | |
| 7200 | 7217 | LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; |
| 7201 | 7218 | LLVMValueRef size_val = LLVMConstInt(usize_type_ref, fn_table_entry->frame_type->abi_size, false); |
| 7202 | ZigLLVMFunctionSetPrefixData(fn_table_entry->llvm_value, size_val); | |
| 7219 | if (g->need_frame_size_prefix_data) { | |
| 7220 | ZigLLVMFunctionSetPrefixData(fn_table_entry->llvm_value, size_val); | |
| 7221 | } | |
| 7203 | 7222 | |
| 7204 | 7223 | if (!g->strip_debug_symbols) { |
| 7205 | 7224 | AstNode *source_node = fn_table_entry->proto_node; |
| ... | ... | @@ -8445,8 +8464,21 @@ static void init(CodeGen *g) { |
| 8445 | 8464 | Buf *producer = buf_sprintf("zig %d.%d.%d", ZIG_VERSION_MAJOR, ZIG_VERSION_MINOR, ZIG_VERSION_PATCH); |
| 8446 | 8465 | const char *flags = ""; |
| 8447 | 8466 | unsigned runtime_version = 0; |
| 8467 | ||
| 8468 | // For macOS stack traces, we want to avoid having to parse the compilation unit debug | |
| 8469 | // info. As long as each debug info file has a path independent of the compilation unit | |
| 8470 | // directory (DW_AT_comp_dir), then we never have to look at the compilation unit debug | |
| 8471 | // info. If we provide an absolute path to LLVM here for the compilation unit debug info, | |
| 8472 | // LLVM will emit DWARF info that depends on DW_AT_comp_dir. To avoid this, we pass "." | |
| 8473 | // for the compilation unit directory. This forces each debug file to have a directory | |
| 8474 | // rather than be relative to DW_AT_comp_dir. According to DWARF 5, debug files will | |
| 8475 | // no longer reference DW_AT_comp_dir, for the purpose of being able to support the | |
| 8476 | // common practice of stripping all but the line number sections from an executable. | |
| 8477 | const char *compile_unit_dir = target_os_is_darwin(g->zig_target->os) ? "." : | |
| 8478 | buf_ptr(&g->root_package->root_src_dir); | |
| 8479 | ||
| 8448 | 8480 | ZigLLVMDIFile *compile_unit_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(g->root_out_name), |
| 8449 | buf_ptr(&g->root_package->root_src_dir)); | |
| 8481 | compile_unit_dir); | |
| 8450 | 8482 | g->compile_unit = ZigLLVMCreateCompileUnit(g->dbuilder, ZigLLVMLang_DW_LANG_C99(), |
| 8451 | 8483 | compile_unit_file, buf_ptr(producer), is_optimized, flags, runtime_version, |
| 8452 | 8484 | "", 0, !g->strip_debug_symbols); |
| ... | ... | @@ -8873,6 +8905,15 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) { |
| 8873 | 8905 | for (size_t i = 0; i < g->test_fns.length; i += 1) { |
| 8874 | 8906 | ZigFn *test_fn_entry = g->test_fns.at(i); |
| 8875 | 8907 | |
| 8908 | if (fn_is_async(test_fn_entry)) { | |
| 8909 | ErrorMsg *msg = add_node_error(g, test_fn_entry->proto_node, | |
| 8910 | buf_create_from_str("test functions cannot be async")); | |
| 8911 | add_error_note(g, msg, test_fn_entry->proto_node, | |
| 8912 | buf_sprintf("this restriction may be lifted in the future. See https://github.com/ziglang/zig/issues/3117 for more details")); | |
| 8913 | add_async_error_notes(g, msg, test_fn_entry); | |
| 8914 | continue; | |
| 8915 | } | |
| 8916 | ||
| 8876 | 8917 | ConstExprValue *this_val = &test_fn_array->data.x_array.data.s_none.elements[i]; |
| 8877 | 8918 | this_val->special = ConstValSpecialStatic; |
| 8878 | 8919 | this_val->type = struct_type; |
| ... | ... | @@ -8892,6 +8933,7 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) { |
| 8892 | 8933 | fn_field->data.x_ptr.mut = ConstPtrMutComptimeConst; |
| 8893 | 8934 | fn_field->data.x_ptr.data.fn.fn_entry = test_fn_entry; |
| 8894 | 8935 | } |
| 8936 | report_errors_and_maybe_exit(g); | |
| 8895 | 8937 | |
| 8896 | 8938 | ConstExprValue *test_fn_slice = create_const_slice(g, test_fn_array, 0, g->test_fns.length, true); |
| 8897 | 8939 | |
| ... | ... | @@ -9803,6 +9845,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { |
| 9803 | 9845 | cache_list_of_str(ch, g->llvm_argv, g->llvm_argv_len); |
| 9804 | 9846 | cache_list_of_str(ch, g->clang_argv, g->clang_argv_len); |
| 9805 | 9847 | cache_list_of_str(ch, g->lib_dirs.items, g->lib_dirs.length); |
| 9848 | cache_list_of_str(ch, g->framework_dirs.items, g->framework_dirs.length); | |
| 9806 | 9849 | if (g->libc) { |
| 9807 | 9850 | cache_buf(ch, &g->libc->include_dir); |
| 9808 | 9851 | cache_buf(ch, &g->libc->sys_include_dir); |
src/ir.cpp+61-37| ... | ... | @@ -330,6 +330,8 @@ static bool ir_should_inline(IrExecutable *exec, Scope *scope) { |
| 330 | 330 | while (scope != nullptr) { |
| 331 | 331 | if (scope->id == ScopeIdCompTime) |
| 332 | 332 | return true; |
| 333 | if (scope->id == ScopeIdTypeOf) | |
| 334 | return false; | |
| 333 | 335 | if (scope->id == ScopeIdFnDef) |
| 334 | 336 | break; |
| 335 | 337 | scope = scope->parent; |
| ... | ... | @@ -14837,6 +14839,12 @@ static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_in |
| 14837 | 14839 | if (align != 0) { |
| 14838 | 14840 | if ((err = type_resolve(ira->codegen, var_type, ResolveStatusAlignmentKnown))) |
| 14839 | 14841 | return ira->codegen->invalid_instruction; |
| 14842 | if (!type_has_bits(var_type)) { | |
| 14843 | ir_add_error(ira, source_inst, | |
| 14844 | buf_sprintf("variable '%s' of zero-bit type '%s' has no in-memory representation, it cannot be aligned", | |
| 14845 | name_hint, buf_ptr(&var_type->name))); | |
| 14846 | return ira->codegen->invalid_instruction; | |
| 14847 | } | |
| 14840 | 14848 | } |
| 14841 | 14849 | assert(result->base.value.data.x_ptr.special != ConstPtrSpecialInvalid); |
| 14842 | 14850 | |
| ... | ... | @@ -15648,6 +15656,32 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source |
| 15648 | 15656 | return &store_ptr->base; |
| 15649 | 15657 | } |
| 15650 | 15658 | |
| 15659 | static IrInstruction *analyze_casted_new_stack(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, | |
| 15660 | ZigFn *fn_entry) | |
| 15661 | { | |
| 15662 | if (call_instruction->new_stack == nullptr) | |
| 15663 | return nullptr; | |
| 15664 | ||
| 15665 | IrInstruction *new_stack = call_instruction->new_stack->child; | |
| 15666 | if (type_is_invalid(new_stack->value.type)) | |
| 15667 | return ira->codegen->invalid_instruction; | |
| 15668 | ||
| 15669 | if (call_instruction->is_async_call_builtin && | |
| 15670 | fn_entry != nullptr && new_stack->value.type->id == ZigTypeIdPointer && | |
| 15671 | new_stack->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame) | |
| 15672 | { | |
| 15673 | ZigType *needed_frame_type = get_pointer_to_type(ira->codegen, | |
| 15674 | get_fn_frame_type(ira->codegen, fn_entry), false); | |
| 15675 | return ir_implicit_cast(ira, new_stack, needed_frame_type); | |
| 15676 | } else { | |
| 15677 | ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, | |
| 15678 | false, false, PtrLenUnknown, target_fn_align(ira->codegen->zig_target), 0, 0, false); | |
| 15679 | ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr); | |
| 15680 | ira->codegen->need_frame_size_prefix_data = true; | |
| 15681 | return ir_implicit_cast(ira, new_stack, u8_slice); | |
| 15682 | } | |
| 15683 | } | |
| 15684 | ||
| 15651 | 15685 | static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, |
| 15652 | 15686 | ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref, |
| 15653 | 15687 | IrInstruction *first_arg_ptr, bool comptime_fn_call, FnInline fn_inline) |
| ... | ... | @@ -15826,31 +15860,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 15826 | 15860 | return ir_finish_anal(ira, new_instruction); |
| 15827 | 15861 | } |
| 15828 | 15862 | |
| 15829 | IrInstruction *casted_new_stack = nullptr; | |
| 15830 | if (call_instruction->new_stack != nullptr) { | |
| 15831 | IrInstruction *new_stack = call_instruction->new_stack->child; | |
| 15832 | if (type_is_invalid(new_stack->value.type)) | |
| 15833 | return ira->codegen->invalid_instruction; | |
| 15834 | ||
| 15835 | if (call_instruction->is_async_call_builtin && | |
| 15836 | fn_entry != nullptr && new_stack->value.type->id == ZigTypeIdPointer && | |
| 15837 | new_stack->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame) | |
| 15838 | { | |
| 15839 | ZigType *needed_frame_type = get_pointer_to_type(ira->codegen, | |
| 15840 | get_fn_frame_type(ira->codegen, fn_entry), false); | |
| 15841 | casted_new_stack = ir_implicit_cast(ira, new_stack, needed_frame_type); | |
| 15842 | if (type_is_invalid(casted_new_stack->value.type)) | |
| 15843 | return ira->codegen->invalid_instruction; | |
| 15844 | } else { | |
| 15845 | ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, | |
| 15846 | false, false, PtrLenUnknown, target_fn_align(ira->codegen->zig_target), 0, 0, false); | |
| 15847 | ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr); | |
| 15848 | casted_new_stack = ir_implicit_cast(ira, new_stack, u8_slice); | |
| 15849 | if (type_is_invalid(casted_new_stack->value.type)) | |
| 15850 | return ira->codegen->invalid_instruction; | |
| 15851 | } | |
| 15852 | } | |
| 15853 | ||
| 15854 | 15863 | if (fn_type->data.fn.is_generic) { |
| 15855 | 15864 | if (!fn_entry) { |
| 15856 | 15865 | ir_add_error(ira, call_instruction->fn_ref, |
| ... | ... | @@ -16063,6 +16072,10 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 16063 | 16072 | parent_fn_entry->calls_or_awaits_errorable_fn = true; |
| 16064 | 16073 | } |
| 16065 | 16074 | |
| 16075 | IrInstruction *casted_new_stack = analyze_casted_new_stack(ira, call_instruction, impl_fn); | |
| 16076 | if (casted_new_stack != nullptr && type_is_invalid(casted_new_stack->value.type)) | |
| 16077 | return ira->codegen->invalid_instruction; | |
| 16078 | ||
| 16066 | 16079 | size_t impl_param_count = impl_fn_type_id->param_count; |
| 16067 | 16080 | if (call_instruction->is_async) { |
| 16068 | 16081 | IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry, |
| ... | ... | @@ -16071,11 +16084,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 16071 | 16084 | } |
| 16072 | 16085 | |
| 16073 | 16086 | IrInstruction *result_loc; |
| 16074 | if (call_instruction->is_async_call_builtin) { | |
| 16075 | result_loc = get_async_call_result_loc(ira, call_instruction, impl_fn_type_id->return_type); | |
| 16076 | if (result_loc != nullptr && type_is_invalid(result_loc->value.type)) | |
| 16077 | return ira->codegen->invalid_instruction; | |
| 16078 | } else if (handle_is_ptr(impl_fn_type_id->return_type)) { | |
| 16087 | if (handle_is_ptr(impl_fn_type_id->return_type)) { | |
| 16079 | 16088 | result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, |
| 16080 | 16089 | impl_fn_type_id->return_type, nullptr, true, true, false); |
| 16081 | 16090 | if (result_loc != nullptr) { |
| ... | ... | @@ -16087,6 +16096,10 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 16087 | 16096 | result_loc = nullptr; |
| 16088 | 16097 | } |
| 16089 | 16098 | } |
| 16099 | } else if (call_instruction->is_async_call_builtin) { | |
| 16100 | result_loc = get_async_call_result_loc(ira, call_instruction, impl_fn_type_id->return_type); | |
| 16101 | if (result_loc != nullptr && type_is_invalid(result_loc->value.type)) | |
| 16102 | return ira->codegen->invalid_instruction; | |
| 16090 | 16103 | } else { |
| 16091 | 16104 | result_loc = nullptr; |
| 16092 | 16105 | } |
| ... | ... | @@ -16211,6 +16224,10 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 16211 | 16224 | return ira->codegen->invalid_instruction; |
| 16212 | 16225 | } |
| 16213 | 16226 | |
| 16227 | IrInstruction *casted_new_stack = analyze_casted_new_stack(ira, call_instruction, fn_entry); | |
| 16228 | if (casted_new_stack != nullptr && type_is_invalid(casted_new_stack->value.type)) | |
| 16229 | return ira->codegen->invalid_instruction; | |
| 16230 | ||
| 16214 | 16231 | if (call_instruction->is_async) { |
| 16215 | 16232 | IrInstruction *result = ir_analyze_async_call(ira, call_instruction, fn_entry, fn_type, fn_ref, |
| 16216 | 16233 | casted_args, call_param_count, casted_new_stack); |
| ... | ... | @@ -16223,11 +16240,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 16223 | 16240 | } |
| 16224 | 16241 | |
| 16225 | 16242 | IrInstruction *result_loc; |
| 16226 | if (call_instruction->is_async_call_builtin) { | |
| 16227 | result_loc = get_async_call_result_loc(ira, call_instruction, return_type); | |
| 16228 | if (result_loc != nullptr && type_is_invalid(result_loc->value.type)) | |
| 16229 | return ira->codegen->invalid_instruction; | |
| 16230 | } else if (handle_is_ptr(return_type)) { | |
| 16243 | if (handle_is_ptr(return_type)) { | |
| 16231 | 16244 | result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, |
| 16232 | 16245 | return_type, nullptr, true, true, false); |
| 16233 | 16246 | if (result_loc != nullptr) { |
| ... | ... | @@ -16239,6 +16252,10 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 16239 | 16252 | result_loc = nullptr; |
| 16240 | 16253 | } |
| 16241 | 16254 | } |
| 16255 | } else if (call_instruction->is_async_call_builtin) { | |
| 16256 | result_loc = get_async_call_result_loc(ira, call_instruction, return_type); | |
| 16257 | if (result_loc != nullptr && type_is_invalid(result_loc->value.type)) | |
| 16258 | return ira->codegen->invalid_instruction; | |
| 16242 | 16259 | } else { |
| 16243 | 16260 | result_loc = nullptr; |
| 16244 | 16261 | } |
| ... | ... | @@ -17453,7 +17470,12 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ |
| 17453 | 17470 | return ir_analyze_container_member_access_inner(ira, bare_type, field_name, |
| 17454 | 17471 | source_instr, container_ptr, container_type); |
| 17455 | 17472 | } |
| 17456 | ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field->type_entry, | |
| 17473 | ||
| 17474 | ZigType *field_type = resolve_union_field_type(ira->codegen, field); | |
| 17475 | if (field_type == nullptr) | |
| 17476 | return ira->codegen->invalid_instruction; | |
| 17477 | ||
| 17478 | ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field_type, | |
| 17457 | 17479 | is_const, is_volatile, PtrLenSingle, 0, 0, 0, false); |
| 17458 | 17480 | if (instr_is_comptime(container_ptr)) { |
| 17459 | 17481 | ConstExprValue *ptr_val = ir_resolve_const(ira, container_ptr, UndefBad); |
| ... | ... | @@ -17470,7 +17492,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ |
| 17470 | 17492 | if (initializing) { |
| 17471 | 17493 | ConstExprValue *payload_val = create_const_vals(1); |
| 17472 | 17494 | payload_val->special = ConstValSpecialUndef; |
| 17473 | payload_val->type = field->type_entry; | |
| 17495 | payload_val->type = field_type; | |
| 17474 | 17496 | payload_val->parent.id = ConstParentIdUnion; |
| 17475 | 17497 | payload_val->parent.data.p_union.union_val = union_val; |
| 17476 | 17498 | |
| ... | ... | @@ -22523,6 +22545,8 @@ static IrInstruction *ir_analyze_instruction_frame_size(IrAnalyze *ira, IrInstru |
| 22523 | 22545 | return ira->codegen->invalid_instruction; |
| 22524 | 22546 | } |
| 22525 | 22547 | |
| 22548 | ira->codegen->need_frame_size_prefix_data = true; | |
| 22549 | ||
| 22526 | 22550 | IrInstruction *result = ir_build_frame_size_gen(&ira->new_irb, instruction->base.scope, |
| 22527 | 22551 | instruction->base.source_node, fn); |
| 22528 | 22552 | result->value.type = ira->codegen->builtin_types.entry_usize; |
src/link.cpp+6| ... | ... | @@ -2510,6 +2510,12 @@ static void construct_linker_job_macho(LinkJob *lj) { |
| 2510 | 2510 | lj->args.append("dynamic_lookup"); |
| 2511 | 2511 | } |
| 2512 | 2512 | |
| 2513 | for (size_t i = 0; i < g->framework_dirs.length; i += 1) { | |
| 2514 | const char *framework_dir = g->framework_dirs.at(i); | |
| 2515 | lj->args.append("-F"); | |
| 2516 | lj->args.append(framework_dir); | |
| 2517 | } | |
| 2518 | ||
| 2513 | 2519 | for (size_t i = 0; i < g->darwin_frameworks.length; i += 1) { |
| 2514 | 2520 | lj->args.append("-framework"); |
| 2515 | 2521 | lj->args.append(buf_ptr(g->darwin_frameworks.at(i))); |
src/main.cpp+9| ... | ... | @@ -104,6 +104,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { |
| 104 | 104 | " -rdynamic add all symbols to the dynamic symbol table\n" |
| 105 | 105 | " -rpath [path] add directory to the runtime library search path\n" |
| 106 | 106 | " --subsystem [subsystem] (windows) /SUBSYSTEM:<subsystem> to the linker\n" |
| 107 | " -F[dir] (darwin) add search path for frameworks\n" | |
| 107 | 108 | " -framework [name] (darwin) link against framework\n" |
| 108 | 109 | " -mios-version-min [ver] (darwin) set iOS deployment target\n" |
| 109 | 110 | " -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target\n" |
| ... | ... | @@ -454,6 +455,7 @@ int main(int argc, char **argv) { |
| 454 | 455 | ZigList<const char *> lib_dirs = {0}; |
| 455 | 456 | ZigList<const char *> link_libs = {0}; |
| 456 | 457 | ZigList<const char *> forbidden_link_libs = {0}; |
| 458 | ZigList<const char *> framework_dirs = {0}; | |
| 457 | 459 | ZigList<const char *> frameworks = {0}; |
| 458 | 460 | bool have_libc = false; |
| 459 | 461 | const char *target_string = nullptr; |
| ... | ... | @@ -686,6 +688,8 @@ int main(int argc, char **argv) { |
| 686 | 688 | } else if (arg[1] == 'L' && arg[2] != 0) { |
| 687 | 689 | // alias for --library-path |
| 688 | 690 | lib_dirs.append(&arg[2]); |
| 691 | } else if (arg[1] == 'F' && arg[2] != 0) { | |
| 692 | framework_dirs.append(&arg[2]); | |
| 689 | 693 | } else if (strcmp(arg, "--pkg-begin") == 0) { |
| 690 | 694 | if (i + 2 >= argc) { |
| 691 | 695 | fprintf(stderr, "Expected 2 arguments after --pkg-begin\n"); |
| ... | ... | @@ -772,6 +776,8 @@ int main(int argc, char **argv) { |
| 772 | 776 | main_pkg_path = buf_create_from_str(argv[i]); |
| 773 | 777 | } else if (strcmp(arg, "--library-path") == 0 || strcmp(arg, "-L") == 0) { |
| 774 | 778 | lib_dirs.append(argv[i]); |
| 779 | } else if (strcmp(arg, "-F") == 0) { | |
| 780 | framework_dirs.append(argv[i]); | |
| 775 | 781 | } else if (strcmp(arg, "--library") == 0) { |
| 776 | 782 | if (strcmp(argv[i], "c") == 0) |
| 777 | 783 | have_libc = true; |
| ... | ... | @@ -1153,6 +1159,9 @@ int main(int argc, char **argv) { |
| 1153 | 1159 | for (size_t i = 0; i < lib_dirs.length; i += 1) { |
| 1154 | 1160 | codegen_add_lib_dir(g, lib_dirs.at(i)); |
| 1155 | 1161 | } |
| 1162 | for (size_t i = 0; i < framework_dirs.length; i += 1) { | |
| 1163 | g->framework_dirs.append(framework_dirs.at(i)); | |
| 1164 | } | |
| 1156 | 1165 | for (size_t i = 0; i < link_libs.length; i += 1) { |
| 1157 | 1166 | LinkLib *link_lib = codegen_add_link_lib(g, buf_create_from_str(link_libs.at(i))); |
| 1158 | 1167 | link_lib->provided_explicitly = true; |
src/zig_llvm.cpp+1| ... | ... | @@ -842,6 +842,7 @@ const char *ZigLLVMGetSubArchTypeName(ZigLLVM_SubArchType sub_arch) { |
| 842 | 842 | |
| 843 | 843 | void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module) { |
| 844 | 844 | unwrap(module)->addModuleFlag(Module::Warning, "Debug Info Version", DEBUG_METADATA_VERSION); |
| 845 | unwrap(module)->addModuleFlag(Module::Warning, "Dwarf Version", 4); | |
| 845 | 846 | } |
| 846 | 847 | |
| 847 | 848 | void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module) { |
std/buf_map.zig+2-2| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | const std = @import("std.zig"); |
| 2 | const HashMap = std.HashMap; | |
| 2 | const StringHashMap = std.StringHashMap; | |
| 3 | 3 | const mem = std.mem; |
| 4 | 4 | const Allocator = mem.Allocator; |
| 5 | 5 | const testing = std.testing; |
| ... | ... | @@ -9,7 +9,7 @@ const testing = std.testing; |
| 9 | 9 | pub const BufMap = struct { |
| 10 | 10 | hash_map: BufMapHashMap, |
| 11 | 11 | |
| 12 | const BufMapHashMap = HashMap([]const u8, []const u8, mem.hash_slice_u8, mem.eql_slice_u8); | |
| 12 | const BufMapHashMap = StringHashMap([]const u8); | |
| 13 | 13 | |
| 14 | 14 | pub fn init(allocator: *Allocator) BufMap { |
| 15 | 15 | var self = BufMap{ .hash_map = BufMapHashMap.init(allocator) }; |
std/buf_set.zig+2-2| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | const std = @import("std.zig"); |
| 2 | const HashMap = @import("hash_map.zig").HashMap; | |
| 2 | const StringHashMap = std.StringHashMap; | |
| 3 | 3 | const mem = @import("mem.zig"); |
| 4 | 4 | const Allocator = mem.Allocator; |
| 5 | 5 | const testing = std.testing; |
| ... | ... | @@ -7,7 +7,7 @@ const testing = std.testing; |
| 7 | 7 | pub const BufSet = struct { |
| 8 | 8 | hash_map: BufSetHashMap, |
| 9 | 9 | |
| 10 | const BufSetHashMap = HashMap([]const u8, void, mem.hash_slice_u8, mem.eql_slice_u8); | |
| 10 | const BufSetHashMap = StringHashMap(void); | |
| 11 | 11 | |
| 12 | 12 | pub fn init(a: *Allocator) BufSet { |
| 13 | 13 | var self = BufSet{ .hash_map = BufSetHashMap.init(a) }; |
std/build.zig+34-19| ... | ... | @@ -4,10 +4,11 @@ const io = std.io; |
| 4 | 4 | const fs = std.fs; |
| 5 | 5 | const mem = std.mem; |
| 6 | 6 | const debug = std.debug; |
| 7 | const panic = std.debug.panic; | |
| 7 | 8 | const assert = debug.assert; |
| 8 | 9 | const warn = std.debug.warn; |
| 9 | 10 | const ArrayList = std.ArrayList; |
| 10 | const HashMap = std.HashMap; | |
| 11 | const StringHashMap = std.StringHashMap; | |
| 11 | 12 | const Allocator = mem.Allocator; |
| 12 | 13 | const process = std.process; |
| 13 | 14 | const BufSet = std.BufSet; |
| ... | ... | @@ -42,8 +43,8 @@ pub const Builder = struct { |
| 42 | 43 | top_level_steps: ArrayList(*TopLevelStep), |
| 43 | 44 | install_prefix: ?[]const u8, |
| 44 | 45 | dest_dir: ?[]const u8, |
| 45 | lib_dir: ?[]const u8, | |
| 46 | exe_dir: ?[]const u8, | |
| 46 | lib_dir: []const u8, | |
| 47 | exe_dir: []const u8, | |
| 47 | 48 | install_path: []const u8, |
| 48 | 49 | search_prefixes: ArrayList([]const u8), |
| 49 | 50 | installed_files: ArrayList(InstalledFile), |
| ... | ... | @@ -60,8 +61,8 @@ pub const Builder = struct { |
| 60 | 61 | C11, |
| 61 | 62 | }; |
| 62 | 63 | |
| 63 | const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8); | |
| 64 | const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8); | |
| 64 | const UserInputOptionsMap = StringHashMap(UserInputOption); | |
| 65 | const AvailableOptionsMap = StringHashMap(AvailableOption); | |
| 65 | 66 | |
| 66 | 67 | const AvailableOption = struct { |
| 67 | 68 | name: []const u8, |
| ... | ... | @@ -129,8 +130,8 @@ pub const Builder = struct { |
| 129 | 130 | .env_map = env_map, |
| 130 | 131 | .search_prefixes = ArrayList([]const u8).init(allocator), |
| 131 | 132 | .install_prefix = null, |
| 132 | .lib_dir = null, | |
| 133 | .exe_dir = null, | |
| 133 | .lib_dir = undefined, | |
| 134 | .exe_dir = undefined, | |
| 134 | 135 | .dest_dir = env_map.get("DESTDIR"), |
| 135 | 136 | .installed_files = ArrayList(InstalledFile).init(allocator), |
| 136 | 137 | .install_tls = TopLevelStep{ |
| ... | ... | @@ -163,11 +164,13 @@ pub const Builder = struct { |
| 163 | 164 | self.allocator.destroy(self); |
| 164 | 165 | } |
| 165 | 166 | |
| 167 | /// This function is intended to be called by std/special/build_runner.zig, not a build.zig file. | |
| 166 | 168 | pub fn setInstallPrefix(self: *Builder, optional_prefix: ?[]const u8) void { |
| 167 | 169 | self.install_prefix = optional_prefix; |
| 168 | 170 | } |
| 169 | 171 | |
| 170 | fn resolveInstallPrefix(self: *Builder) void { | |
| 172 | /// This function is intended to be called by std/special/build_runner.zig, not a build.zig file. | |
| 173 | pub fn resolveInstallPrefix(self: *Builder) void { | |
| 171 | 174 | if (self.dest_dir) |dest_dir| { |
| 172 | 175 | const install_prefix = self.install_prefix orelse "/usr"; |
| 173 | 176 | self.install_path = fs.path.join(self.allocator, [_][]const u8{ dest_dir, install_prefix }) catch unreachable; |
| ... | ... | @@ -437,7 +440,7 @@ pub const Builder = struct { |
| 437 | 440 | .description = description, |
| 438 | 441 | }; |
| 439 | 442 | if ((self.available_options_map.put(name, available_option) catch unreachable) != null) { |
| 440 | debug.panic("Option '{}' declared twice", name); | |
| 443 | panic("Option '{}' declared twice", name); | |
| 441 | 444 | } |
| 442 | 445 | self.available_options_list.append(available_option) catch unreachable; |
| 443 | 446 | |
| ... | ... | @@ -463,8 +466,8 @@ pub const Builder = struct { |
| 463 | 466 | return null; |
| 464 | 467 | }, |
| 465 | 468 | }, |
| 466 | TypeId.Int => debug.panic("TODO integer options to build script"), | |
| 467 | TypeId.Float => debug.panic("TODO float options to build script"), | |
| 469 | TypeId.Int => panic("TODO integer options to build script"), | |
| 470 | TypeId.Float => panic("TODO float options to build script"), | |
| 468 | 471 | TypeId.String => switch (entry.value.value) { |
| 469 | 472 | UserValue.Flag => { |
| 470 | 473 | warn("Expected -D{} to be a string, but received a boolean.\n", name); |
| ... | ... | @@ -478,7 +481,7 @@ pub const Builder = struct { |
| 478 | 481 | }, |
| 479 | 482 | UserValue.Scalar => |s| return s, |
| 480 | 483 | }, |
| 481 | TypeId.List => debug.panic("TODO list options to build script"), | |
| 484 | TypeId.List => panic("TODO list options to build script"), | |
| 482 | 485 | } |
| 483 | 486 | } |
| 484 | 487 | |
| ... | ... | @@ -644,8 +647,6 @@ pub const Builder = struct { |
| 644 | 647 | } |
| 645 | 648 | |
| 646 | 649 | pub fn validateUserInputDidItFail(self: *Builder) bool { |
| 647 | self.resolveInstallPrefix(); | |
| 648 | ||
| 649 | 650 | // make sure all args are used |
| 650 | 651 | var it = self.user_input_options.iterator(); |
| 651 | 652 | while (true) { |
| ... | ... | @@ -855,7 +856,7 @@ pub const Builder = struct { |
| 855 | 856 | var stdout_file_in_stream = child.stdout.?.inStream(); |
| 856 | 857 | try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size); |
| 857 | 858 | |
| 858 | const term = child.wait() catch |err| std.debug.panic("unable to spawn {}: {}", argv[0], err); | |
| 859 | const term = child.wait() catch |err| panic("unable to spawn {}: {}", argv[0], err); | |
| 859 | 860 | switch (term) { |
| 860 | 861 | .Exited => |code| { |
| 861 | 862 | if (code != 0) { |
| ... | ... | @@ -882,8 +883,8 @@ pub const Builder = struct { |
| 882 | 883 | fn getInstallPath(self: *Builder, dir: InstallDir, dest_rel_path: []const u8) []const u8 { |
| 883 | 884 | const base_dir = switch (dir) { |
| 884 | 885 | .Prefix => self.install_path, |
| 885 | .Bin => self.exe_dir.?, | |
| 886 | .Lib => self.lib_dir.?, | |
| 886 | .Bin => self.exe_dir, | |
| 887 | .Lib => self.lib_dir, | |
| 887 | 888 | }; |
| 888 | 889 | return fs.path.resolve( |
| 889 | 890 | self.allocator, |
| ... | ... | @@ -1228,6 +1229,7 @@ pub const LibExeObjStep = struct { |
| 1228 | 1229 | name_only_filename: []const u8, |
| 1229 | 1230 | strip: bool, |
| 1230 | 1231 | lib_paths: ArrayList([]const u8), |
| 1232 | framework_dirs: ArrayList([]const u8), | |
| 1231 | 1233 | frameworks: BufSet, |
| 1232 | 1234 | verbose_link: bool, |
| 1233 | 1235 | verbose_cc: bool, |
| ... | ... | @@ -1317,6 +1319,9 @@ pub const LibExeObjStep = struct { |
| 1317 | 1319 | } |
| 1318 | 1320 | |
| 1319 | 1321 | fn initExtraArgs(builder: *Builder, name: []const u8, root_src: ?[]const u8, kind: Kind, is_dynamic: bool, ver: Version) LibExeObjStep { |
| 1322 | if (mem.indexOf(u8, name, "/") != null or mem.indexOf(u8, name, "\\") != null) { | |
| 1323 | panic("invalid name: '{}'. It looks like a file path, but it is supposed to be the library or application name.", name); | |
| 1324 | } | |
| 1320 | 1325 | var self = LibExeObjStep{ |
| 1321 | 1326 | .strip = false, |
| 1322 | 1327 | .builder = builder, |
| ... | ... | @@ -1341,6 +1346,7 @@ pub const LibExeObjStep = struct { |
| 1341 | 1346 | .include_dirs = ArrayList(IncludeDir).init(builder.allocator), |
| 1342 | 1347 | .link_objects = ArrayList(LinkObject).init(builder.allocator), |
| 1343 | 1348 | .lib_paths = ArrayList([]const u8).init(builder.allocator), |
| 1349 | .framework_dirs = ArrayList([]const u8).init(builder.allocator), | |
| 1344 | 1350 | .object_src = undefined, |
| 1345 | 1351 | .build_options_contents = std.Buffer.initSize(builder.allocator, 0) catch unreachable, |
| 1346 | 1352 | .c_std = Builder.CStd.C99, |
| ... | ... | @@ -1614,6 +1620,10 @@ pub const LibExeObjStep = struct { |
| 1614 | 1620 | self.lib_paths.append(path) catch unreachable; |
| 1615 | 1621 | } |
| 1616 | 1622 | |
| 1623 | pub fn addFrameworkDir(self: *LibExeObjStep, dir_path: []const u8) void { | |
| 1624 | self.framework_dirs.append(dir_path) catch unreachable; | |
| 1625 | } | |
| 1626 | ||
| 1617 | 1627 | pub fn addPackagePath(self: *LibExeObjStep, name: []const u8, pkg_index_path: []const u8) void { |
| 1618 | 1628 | self.packages.append(Pkg{ |
| 1619 | 1629 | .name = name, |
| ... | ... | @@ -1860,8 +1870,8 @@ pub const LibExeObjStep = struct { |
| 1860 | 1870 | } |
| 1861 | 1871 | |
| 1862 | 1872 | for (self.lib_paths.toSliceConst()) |lib_path| { |
| 1863 | zig_args.append("--library-path") catch unreachable; | |
| 1864 | zig_args.append(lib_path) catch unreachable; | |
| 1873 | try zig_args.append("-L"); | |
| 1874 | try zig_args.append(lib_path); | |
| 1865 | 1875 | } |
| 1866 | 1876 | |
| 1867 | 1877 | if (self.need_system_paths and self.target == Target.Native) { |
| ... | ... | @@ -1882,6 +1892,11 @@ pub const LibExeObjStep = struct { |
| 1882 | 1892 | } |
| 1883 | 1893 | |
| 1884 | 1894 | if (self.target.isDarwin()) { |
| 1895 | for (self.framework_dirs.toSliceConst()) |dir| { | |
| 1896 | try zig_args.append("-F"); | |
| 1897 | try zig_args.append(dir); | |
| 1898 | } | |
| 1899 | ||
| 1885 | 1900 | var it = self.frameworks.iterator(); |
| 1886 | 1901 | while (it.next()) |entry| { |
| 1887 | 1902 | zig_args.append("-framework") catch unreachable; |
std/fmt/parse_float.zig+11-3| ... | ... | @@ -110,9 +110,7 @@ fn convertRepr(comptime T: type, n: FloatRepr) T { |
| 110 | 110 | q.shiftLeft1(s); // q = p << 1 |
| 111 | 111 | r.shiftLeft1(q); // r = p << 2 |
| 112 | 112 | s.shiftLeft1(r); // p = p << 3 |
| 113 | q.add(s); // p = (p << 3) + (p << 1) | |
| 114 | ||
| 115 | exp -= 1; | |
| 113 | s.add(q); // p = (p << 3) + (p << 1) | |
| 116 | 114 | |
| 117 | 115 | while (s.d2 & mask28 != 0) { |
| 118 | 116 | q.shiftRight1(s); |
| ... | ... | @@ -402,6 +400,13 @@ test "fmt.parseFloat" { |
| 402 | 400 | expectEqual((try parseFloat(T, "+0")), 0.0); |
| 403 | 401 | expectEqual((try parseFloat(T, "-0")), 0.0); |
| 404 | 402 | |
| 403 | expectEqual((try parseFloat(T, "0e0")), 0); | |
| 404 | expectEqual((try parseFloat(T, "2e3")), 2000.0); | |
| 405 | expectEqual((try parseFloat(T, "1e0")), 1.0); | |
| 406 | expectEqual((try parseFloat(T, "-2e3")), -2000.0); | |
| 407 | expectEqual((try parseFloat(T, "-1e0")), -1.0); | |
| 408 | expectEqual((try parseFloat(T, "1.234e3")), 1234); | |
| 409 | ||
| 405 | 410 | expect(approxEq(T, try parseFloat(T, "3.141"), 3.141, epsilon)); |
| 406 | 411 | expect(approxEq(T, try parseFloat(T, "-3.141"), -3.141, epsilon)); |
| 407 | 412 | |
| ... | ... | @@ -413,6 +418,9 @@ test "fmt.parseFloat" { |
| 413 | 418 | expectEqual((try parseFloat(T, "-INF")), -std.math.inf(T)); |
| 414 | 419 | |
| 415 | 420 | if (T != f16) { |
| 421 | expect(approxEq(T, try parseFloat(T, "1e-2"), 0.01, epsilon)); | |
| 422 | expect(approxEq(T, try parseFloat(T, "1234e-2"), 12.34, epsilon)); | |
| 423 | ||
| 416 | 424 | expect(approxEq(T, try parseFloat(T, "123142.1"), 123142.1, epsilon)); |
| 417 | 425 | expect(approxEq(T, try parseFloat(T, "-123142.1124"), T(-123142.1124), epsilon)); |
| 418 | 426 | expect(approxEq(T, try parseFloat(T, "0.7062146892655368"), T(0.7062146892655368), epsilon)); |
std/hash_map.zig+1-3| ... | ... | @@ -23,9 +23,7 @@ pub fn StringHashMap(comptime V: type) type { |
| 23 | 23 | } |
| 24 | 24 | |
| 25 | 25 | pub fn eqlString(a: []const u8, b: []const u8) bool { |
| 26 | if (a.len != b.len) return false; | |
| 27 | if (a.ptr == b.ptr) return true; | |
| 28 | return mem.compare(u8, a, b) == .Equal; | |
| 26 | return mem.eql(u8, a, b); | |
| 29 | 27 | } |
| 30 | 28 | |
| 31 | 29 | pub fn hashString(s: []const u8) u32 { |
std/json.zig+2-2| ... | ... | @@ -989,7 +989,7 @@ test "json.validate" { |
| 989 | 989 | const Allocator = std.mem.Allocator; |
| 990 | 990 | const ArenaAllocator = std.heap.ArenaAllocator; |
| 991 | 991 | const ArrayList = std.ArrayList; |
| 992 | const HashMap = std.HashMap; | |
| 992 | const StringHashMap = std.StringHashMap; | |
| 993 | 993 | |
| 994 | 994 | pub const ValueTree = struct { |
| 995 | 995 | arena: ArenaAllocator, |
| ... | ... | @@ -1000,7 +1000,7 @@ pub const ValueTree = struct { |
| 1000 | 1000 | } |
| 1001 | 1001 | }; |
| 1002 | 1002 | |
| 1003 | pub const ObjectMap = HashMap([]const u8, Value, mem.hash_slice_u8, mem.eql_slice_u8); | |
| 1003 | pub const ObjectMap = StringHashMap(Value); | |
| 1004 | 1004 | |
| 1005 | 1005 | pub const Value = union(enum) { |
| 1006 | 1006 | Null, |
std/mem.zig+13-25| ... | ... | @@ -339,6 +339,7 @@ test "mem.lessThan" { |
| 339 | 339 | /// Compares two slices and returns whether they are equal. |
| 340 | 340 | pub fn eql(comptime T: type, a: []const T, b: []const T) bool { |
| 341 | 341 | if (a.len != b.len) return false; |
| 342 | if (a.ptr == b.ptr) return true; | |
| 342 | 343 | for (a) |item, index| { |
| 343 | 344 | if (b[index] != item) return false; |
| 344 | 345 | } |
| ... | ... | @@ -738,47 +739,34 @@ test "writeIntBig and writeIntLittle" { |
| 738 | 739 | var buf9: [9]u8 = undefined; |
| 739 | 740 | |
| 740 | 741 | writeIntBig(u0, &buf0, 0x0); |
| 741 | testing.expect(eql_slice_u8(buf0[0..], [_]u8{})); | |
| 742 | testing.expect(eql(u8, buf0[0..], [_]u8{})); | |
| 742 | 743 | writeIntLittle(u0, &buf0, 0x0); |
| 743 | testing.expect(eql_slice_u8(buf0[0..], [_]u8{})); | |
| 744 | testing.expect(eql(u8, buf0[0..], [_]u8{})); | |
| 744 | 745 | |
| 745 | 746 | writeIntBig(u8, &buf1, 0x12); |
| 746 | testing.expect(eql_slice_u8(buf1[0..], [_]u8{0x12})); | |
| 747 | testing.expect(eql(u8, buf1[0..], [_]u8{0x12})); | |
| 747 | 748 | writeIntLittle(u8, &buf1, 0x34); |
| 748 | testing.expect(eql_slice_u8(buf1[0..], [_]u8{0x34})); | |
| 749 | testing.expect(eql(u8, buf1[0..], [_]u8{0x34})); | |
| 749 | 750 | |
| 750 | 751 | writeIntBig(u16, &buf2, 0x1234); |
| 751 | testing.expect(eql_slice_u8(buf2[0..], [_]u8{ 0x12, 0x34 })); | |
| 752 | testing.expect(eql(u8, buf2[0..], [_]u8{ 0x12, 0x34 })); | |
| 752 | 753 | writeIntLittle(u16, &buf2, 0x5678); |
| 753 | testing.expect(eql_slice_u8(buf2[0..], [_]u8{ 0x78, 0x56 })); | |
| 754 | testing.expect(eql(u8, buf2[0..], [_]u8{ 0x78, 0x56 })); | |
| 754 | 755 | |
| 755 | 756 | writeIntBig(u72, &buf9, 0x123456789abcdef024); |
| 756 | testing.expect(eql_slice_u8(buf9[0..], [_]u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 })); | |
| 757 | testing.expect(eql(u8, buf9[0..], [_]u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 })); | |
| 757 | 758 | writeIntLittle(u72, &buf9, 0xfedcba9876543210ec); |
| 758 | testing.expect(eql_slice_u8(buf9[0..], [_]u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe })); | |
| 759 | testing.expect(eql(u8, buf9[0..], [_]u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe })); | |
| 759 | 760 | |
| 760 | 761 | writeIntBig(i8, &buf1, -1); |
| 761 | testing.expect(eql_slice_u8(buf1[0..], [_]u8{0xff})); | |
| 762 | testing.expect(eql(u8, buf1[0..], [_]u8{0xff})); | |
| 762 | 763 | writeIntLittle(i8, &buf1, -2); |
| 763 | testing.expect(eql_slice_u8(buf1[0..], [_]u8{0xfe})); | |
| 764 | testing.expect(eql(u8, buf1[0..], [_]u8{0xfe})); | |
| 764 | 765 | |
| 765 | 766 | writeIntBig(i16, &buf2, -3); |
| 766 | testing.expect(eql_slice_u8(buf2[0..], [_]u8{ 0xff, 0xfd })); | |
| 767 | testing.expect(eql(u8, buf2[0..], [_]u8{ 0xff, 0xfd })); | |
| 767 | 768 | writeIntLittle(i16, &buf2, -4); |
| 768 | testing.expect(eql_slice_u8(buf2[0..], [_]u8{ 0xfc, 0xff })); | |
| 769 | } | |
| 770 | ||
| 771 | pub fn hash_slice_u8(k: []const u8) u32 { | |
| 772 | // FNV 32-bit hash | |
| 773 | var h: u32 = 2166136261; | |
| 774 | for (k) |b| { | |
| 775 | h = (h ^ b) *% 16777619; | |
| 776 | } | |
| 777 | return h; | |
| 778 | } | |
| 779 | ||
| 780 | pub fn eql_slice_u8(a: []const u8, b: []const u8) bool { | |
| 781 | return eql(u8, a, b); | |
| 769 | testing.expect(eql(u8, buf2[0..], [_]u8{ 0xfc, 0xff })); | |
| 782 | 770 | } |
| 783 | 771 | |
| 784 | 772 | /// Returns an iterator that iterates over the slices of `buffer` that are not |
std/special/build_runner.zig+2| ... | ... | @@ -123,6 +123,7 @@ pub fn main() !void { |
| 123 | 123 | } |
| 124 | 124 | } |
| 125 | 125 | |
| 126 | builder.resolveInstallPrefix(); | |
| 126 | 127 | try runBuild(builder); |
| 127 | 128 | |
| 128 | 129 | if (builder.validateUserInputDidItFail()) |
| ... | ... | @@ -151,6 +152,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void { |
| 151 | 152 | // run the build script to collect the options |
| 152 | 153 | if (!already_ran_build) { |
| 153 | 154 | builder.setInstallPrefix(null); |
| 155 | builder.resolveInstallPrefix(); | |
| 154 | 156 | try runBuild(builder); |
| 155 | 157 | } |
| 156 | 158 |
std/zig/parser_test.zig+88| ... | ... | @@ -2419,6 +2419,94 @@ test "zig fmt: comment after empty comment" { |
| 2419 | 2419 | ); |
| 2420 | 2420 | } |
| 2421 | 2421 | |
| 2422 | test "zig fmt: line comment in array" { | |
| 2423 | try testTransform( | |
| 2424 | \\test "a" { | |
| 2425 | \\ var arr = [_]u32{ | |
| 2426 | \\ 0 | |
| 2427 | \\ // 1, | |
| 2428 | \\ // 2, | |
| 2429 | \\ }; | |
| 2430 | \\} | |
| 2431 | \\ | |
| 2432 | , | |
| 2433 | \\test "a" { | |
| 2434 | \\ var arr = [_]u32{ | |
| 2435 | \\ 0, // 1, | |
| 2436 | \\ // 2, | |
| 2437 | \\ }; | |
| 2438 | \\} | |
| 2439 | \\ | |
| 2440 | ); | |
| 2441 | try testCanonical( | |
| 2442 | \\test "a" { | |
| 2443 | \\ var arr = [_]u32{ | |
| 2444 | \\ 0, | |
| 2445 | \\ // 1, | |
| 2446 | \\ // 2, | |
| 2447 | \\ }; | |
| 2448 | \\} | |
| 2449 | \\ | |
| 2450 | ); | |
| 2451 | } | |
| 2452 | ||
| 2453 | test "zig fmt: comment after params" { | |
| 2454 | try testTransform( | |
| 2455 | \\fn a( | |
| 2456 | \\ b: u32 | |
| 2457 | \\ // c: u32, | |
| 2458 | \\ // d: u32, | |
| 2459 | \\) void {} | |
| 2460 | \\ | |
| 2461 | , | |
| 2462 | \\fn a( | |
| 2463 | \\ b: u32, // c: u32, | |
| 2464 | \\ // d: u32, | |
| 2465 | \\) void {} | |
| 2466 | \\ | |
| 2467 | ); | |
| 2468 | try testCanonical( | |
| 2469 | \\fn a( | |
| 2470 | \\ b: u32, | |
| 2471 | \\ // c: u32, | |
| 2472 | \\ // d: u32, | |
| 2473 | \\) void {} | |
| 2474 | \\ | |
| 2475 | ); | |
| 2476 | } | |
| 2477 | ||
| 2478 | test "zig fmt: comment in array initializer/access" { | |
| 2479 | try testCanonical( | |
| 2480 | \\test "a" { | |
| 2481 | \\ var a = x{ //aa | |
| 2482 | \\ //bb | |
| 2483 | \\ }; | |
| 2484 | \\ var a = []x{ //aa | |
| 2485 | \\ //bb | |
| 2486 | \\ }; | |
| 2487 | \\ var b = [ //aa | |
| 2488 | \\ _ | |
| 2489 | \\ ]x{ //aa | |
| 2490 | \\ //bb | |
| 2491 | \\ 9, | |
| 2492 | \\ }; | |
| 2493 | \\ var c = b[ //aa | |
| 2494 | \\ 0 | |
| 2495 | \\ ]; | |
| 2496 | \\ var d = [_ | |
| 2497 | \\ //aa | |
| 2498 | \\ ]x{ //aa | |
| 2499 | \\ //bb | |
| 2500 | \\ 9, | |
| 2501 | \\ }; | |
| 2502 | \\ var e = d[0 | |
| 2503 | \\ //aa | |
| 2504 | \\ ]; | |
| 2505 | \\} | |
| 2506 | \\ | |
| 2507 | ); | |
| 2508 | } | |
| 2509 | ||
| 2422 | 2510 | test "zig fmt: comments at several places in struct init" { |
| 2423 | 2511 | try testTransform( |
| 2424 | 2512 | \\var bar = Bar{ |
std/zig/render.zig+34-9| ... | ... | @@ -483,9 +483,23 @@ fn renderExpression( |
| 483 | 483 | }, |
| 484 | 484 | |
| 485 | 485 | ast.Node.PrefixOp.Op.ArrayType => |array_index| { |
| 486 | try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.None); // [ | |
| 487 | try renderExpression(allocator, stream, tree, indent, start_col, array_index, Space.None); | |
| 488 | try renderToken(tree, stream, tree.nextToken(array_index.lastToken()), indent, start_col, Space.None); // ] | |
| 486 | const lbracket = prefix_op_node.op_token; | |
| 487 | const rbracket = tree.nextToken(array_index.lastToken()); | |
| 488 | ||
| 489 | try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [ | |
| 490 | ||
| 491 | const starts_with_comment = tree.tokens.at(lbracket + 1).id == .LineComment; | |
| 492 | const ends_with_comment = tree.tokens.at(rbracket - 1).id == .LineComment; | |
| 493 | const new_indent = if (ends_with_comment) indent + indent_delta else indent; | |
| 494 | const new_space = if (ends_with_comment) Space.Newline else Space.None; | |
| 495 | try renderExpression(allocator, stream, tree, new_indent, start_col, array_index, new_space); | |
| 496 | if (starts_with_comment) { | |
| 497 | try stream.writeByte('\n'); | |
| 498 | } | |
| 499 | if (ends_with_comment or starts_with_comment) { | |
| 500 | try stream.writeByteNTimes(' ', indent); | |
| 501 | } | |
| 502 | try renderToken(tree, stream, rbracket, indent, start_col, Space.None); // ] | |
| 489 | 503 | }, |
| 490 | 504 | ast.Node.PrefixOp.Op.BitNot, |
| 491 | 505 | ast.Node.PrefixOp.Op.BoolNot, |
| ... | ... | @@ -580,7 +594,18 @@ fn renderExpression( |
| 580 | 594 | |
| 581 | 595 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); |
| 582 | 596 | try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [ |
| 583 | try renderExpression(allocator, stream, tree, indent, start_col, index_expr, Space.None); | |
| 597 | ||
| 598 | const starts_with_comment = tree.tokens.at(lbracket + 1).id == .LineComment; | |
| 599 | const ends_with_comment = tree.tokens.at(rbracket - 1).id == .LineComment; | |
| 600 | const new_indent = if (ends_with_comment) indent + indent_delta else indent; | |
| 601 | const new_space = if (ends_with_comment) Space.Newline else Space.None; | |
| 602 | try renderExpression(allocator, stream, tree, new_indent, start_col, index_expr, new_space); | |
| 603 | if (starts_with_comment) { | |
| 604 | try stream.writeByte('\n'); | |
| 605 | } | |
| 606 | if (ends_with_comment or starts_with_comment) { | |
| 607 | try stream.writeByteNTimes(' ', indent); | |
| 608 | } | |
| 584 | 609 | return renderToken(tree, stream, rbracket, indent, start_col, space); // ] |
| 585 | 610 | }, |
| 586 | 611 | |
| ... | ... | @@ -615,7 +640,7 @@ fn renderExpression( |
| 615 | 640 | |
| 616 | 641 | if (field_inits.len == 0) { |
| 617 | 642 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); |
| 618 | try renderToken(tree, stream, lbrace, indent, start_col, Space.None); | |
| 643 | try renderToken(tree, stream, lbrace, indent + indent_delta, start_col, Space.None); | |
| 619 | 644 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); |
| 620 | 645 | } |
| 621 | 646 | |
| ... | ... | @@ -714,7 +739,7 @@ fn renderExpression( |
| 714 | 739 | try renderToken(tree, stream, lbrace, indent, start_col, Space.None); |
| 715 | 740 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); |
| 716 | 741 | } |
| 717 | if (exprs.len == 1) { | |
| 742 | if (exprs.len == 1 and tree.tokens.at(exprs.at(0).*.lastToken() + 1).id == .RBrace) { | |
| 718 | 743 | const expr = exprs.at(0).*; |
| 719 | 744 | |
| 720 | 745 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); |
| ... | ... | @@ -775,7 +800,7 @@ fn renderExpression( |
| 775 | 800 | while (it.next()) |expr| : (i += 1) { |
| 776 | 801 | counting_stream.bytes_written = 0; |
| 777 | 802 | var dummy_col: usize = 0; |
| 778 | try renderExpression(allocator, &counting_stream.stream, tree, 0, &dummy_col, expr.*, Space.None); | |
| 803 | try renderExpression(allocator, &counting_stream.stream, tree, indent, &dummy_col, expr.*, Space.None); | |
| 779 | 804 | const width = @intCast(usize, counting_stream.bytes_written); |
| 780 | 805 | const col = i % row_size; |
| 781 | 806 | column_widths[col] = std.math.max(column_widths[col], width); |
| ... | ... | @@ -1191,8 +1216,8 @@ fn renderExpression( |
| 1191 | 1216 | }); |
| 1192 | 1217 | |
| 1193 | 1218 | const src_params_trailing_comma = blk: { |
| 1194 | const maybe_comma = tree.prevToken(rparen); | |
| 1195 | break :blk tree.tokens.at(maybe_comma).id == Token.Id.Comma; | |
| 1219 | const maybe_comma = tree.tokens.at(rparen - 1).id; | |
| 1220 | break :blk maybe_comma == .Comma or maybe_comma == .LineComment; | |
| 1196 | 1221 | }; |
| 1197 | 1222 | |
| 1198 | 1223 | if (!src_params_trailing_comma) { |
test/compile_errors.zig+9| ... | ... | @@ -6462,4 +6462,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 6462 | 6462 | "tmp.zig:5:30: error: expression value is ignored", |
| 6463 | 6463 | "tmp.zig:9:30: error: expression value is ignored", |
| 6464 | 6464 | ); |
| 6465 | ||
| 6466 | cases.add( | |
| 6467 | "aligned variable of zero-bit type", | |
| 6468 | \\export fn f() void { | |
| 6469 | \\ var s: struct {} align(4) = undefined; | |
| 6470 | \\} | |
| 6471 | , | |
| 6472 | "tmp.zig:2:5: error: variable 's' of zero-bit type 'struct:2:12' has no in-memory representation, it cannot be aligned", | |
| 6473 | ); | |
| 6465 | 6474 | } |
test/stack_traces.zig created+274| ... | ... | @@ -0,0 +1,274 @@ |
| 1 | const builtin = @import("builtin"); | |
| 2 | const std = @import("std"); | |
| 3 | const os = std.os; | |
| 4 | const tests = @import("tests.zig"); | |
| 5 | ||
| 6 | pub fn addCases(cases: *tests.StackTracesContext) void { | |
| 7 | const source_return = | |
| 8 | \\const std = @import("std"); | |
| 9 | \\ | |
| 10 | \\pub fn main() !void { | |
| 11 | \\ return error.TheSkyIsFalling; | |
| 12 | \\} | |
| 13 | ; | |
| 14 | const source_try_return = | |
| 15 | \\const std = @import("std"); | |
| 16 | \\ | |
| 17 | \\fn foo() !void { | |
| 18 | \\ return error.TheSkyIsFalling; | |
| 19 | \\} | |
| 20 | \\ | |
| 21 | \\pub fn main() !void { | |
| 22 | \\ try foo(); | |
| 23 | \\} | |
| 24 | ; | |
| 25 | const source_try_try_return_return = | |
| 26 | \\const std = @import("std"); | |
| 27 | \\ | |
| 28 | \\fn foo() !void { | |
| 29 | \\ try bar(); | |
| 30 | \\} | |
| 31 | \\ | |
| 32 | \\fn bar() !void { | |
| 33 | \\ return make_error(); | |
| 34 | \\} | |
| 35 | \\ | |
| 36 | \\fn make_error() !void { | |
| 37 | \\ return error.TheSkyIsFalling; | |
| 38 | \\} | |
| 39 | \\ | |
| 40 | \\pub fn main() !void { | |
| 41 | \\ try foo(); | |
| 42 | \\} | |
| 43 | ; | |
| 44 | switch (builtin.os) { | |
| 45 | .linux => { | |
| 46 | cases.addCase( | |
| 47 | "return", | |
| 48 | source_return, | |
| 49 | [_][]const u8{ | |
| 50 | // debug | |
| 51 | \\error: TheSkyIsFalling | |
| 52 | \\source.zig:4:5: [address] in main (test) | |
| 53 | \\ | |
| 54 | , | |
| 55 | // release-safe | |
| 56 | \\error: TheSkyIsFalling | |
| 57 | \\source.zig:4:5: [address] in std.special.posixCallMainAndExit (test) | |
| 58 | \\ | |
| 59 | , | |
| 60 | // release-fast | |
| 61 | \\error: TheSkyIsFalling | |
| 62 | \\ | |
| 63 | , | |
| 64 | // release-small | |
| 65 | \\error: TheSkyIsFalling | |
| 66 | \\ | |
| 67 | }, | |
| 68 | ); | |
| 69 | cases.addCase( | |
| 70 | "try return", | |
| 71 | source_try_return, | |
| 72 | [_][]const u8{ | |
| 73 | // debug | |
| 74 | \\error: TheSkyIsFalling | |
| 75 | \\source.zig:4:5: [address] in foo (test) | |
| 76 | \\source.zig:8:5: [address] in main (test) | |
| 77 | \\ | |
| 78 | , | |
| 79 | // release-safe | |
| 80 | \\error: TheSkyIsFalling | |
| 81 | \\source.zig:4:5: [address] in std.special.posixCallMainAndExit (test) | |
| 82 | \\source.zig:8:5: [address] in std.special.posixCallMainAndExit (test) | |
| 83 | \\ | |
| 84 | , | |
| 85 | // release-fast | |
| 86 | \\error: TheSkyIsFalling | |
| 87 | \\ | |
| 88 | , | |
| 89 | // release-small | |
| 90 | \\error: TheSkyIsFalling | |
| 91 | \\ | |
| 92 | }, | |
| 93 | ); | |
| 94 | cases.addCase( | |
| 95 | "try try return return", | |
| 96 | source_try_try_return_return, | |
| 97 | [_][]const u8{ | |
| 98 | // debug | |
| 99 | \\error: TheSkyIsFalling | |
| 100 | \\source.zig:12:5: [address] in make_error (test) | |
| 101 | \\source.zig:8:5: [address] in bar (test) | |
| 102 | \\source.zig:4:5: [address] in foo (test) | |
| 103 | \\source.zig:16:5: [address] in main (test) | |
| 104 | \\ | |
| 105 | , | |
| 106 | // release-safe | |
| 107 | \\error: TheSkyIsFalling | |
| 108 | \\source.zig:12:5: [address] in std.special.posixCallMainAndExit (test) | |
| 109 | \\source.zig:8:5: [address] in std.special.posixCallMainAndExit (test) | |
| 110 | \\source.zig:4:5: [address] in std.special.posixCallMainAndExit (test) | |
| 111 | \\source.zig:16:5: [address] in std.special.posixCallMainAndExit (test) | |
| 112 | \\ | |
| 113 | , | |
| 114 | // release-fast | |
| 115 | \\error: TheSkyIsFalling | |
| 116 | \\ | |
| 117 | , | |
| 118 | // release-small | |
| 119 | \\error: TheSkyIsFalling | |
| 120 | \\ | |
| 121 | }, | |
| 122 | ); | |
| 123 | }, | |
| 124 | .macosx => { | |
| 125 | cases.addCase( | |
| 126 | "return", | |
| 127 | source_return, | |
| 128 | [_][]const u8{ | |
| 129 | // debug | |
| 130 | \\error: TheSkyIsFalling | |
| 131 | \\source.zig:4:5: [address] in _main.0 (test.o) | |
| 132 | \\ | |
| 133 | , | |
| 134 | // release-safe | |
| 135 | \\error: TheSkyIsFalling | |
| 136 | \\source.zig:4:5: [address] in _main (test.o) | |
| 137 | \\ | |
| 138 | , | |
| 139 | // release-fast | |
| 140 | \\error: TheSkyIsFalling | |
| 141 | \\ | |
| 142 | , | |
| 143 | // release-small | |
| 144 | \\error: TheSkyIsFalling | |
| 145 | \\ | |
| 146 | }, | |
| 147 | ); | |
| 148 | cases.addCase( | |
| 149 | "try return", | |
| 150 | source_try_return, | |
| 151 | [_][]const u8{ | |
| 152 | // debug | |
| 153 | \\error: TheSkyIsFalling | |
| 154 | \\source.zig:4:5: [address] in _foo (test.o) | |
| 155 | \\source.zig:8:5: [address] in _main.0 (test.o) | |
| 156 | \\ | |
| 157 | , | |
| 158 | // release-safe | |
| 159 | \\error: TheSkyIsFalling | |
| 160 | \\source.zig:4:5: [address] in _main (test.o) | |
| 161 | \\source.zig:8:5: [address] in _main (test.o) | |
| 162 | \\ | |
| 163 | , | |
| 164 | // release-fast | |
| 165 | \\error: TheSkyIsFalling | |
| 166 | \\ | |
| 167 | , | |
| 168 | // release-small | |
| 169 | \\error: TheSkyIsFalling | |
| 170 | \\ | |
| 171 | }, | |
| 172 | ); | |
| 173 | cases.addCase( | |
| 174 | "try try return return", | |
| 175 | source_try_try_return_return, | |
| 176 | [_][]const u8{ | |
| 177 | // debug | |
| 178 | \\error: TheSkyIsFalling | |
| 179 | \\source.zig:12:5: [address] in _make_error (test.o) | |
| 180 | \\source.zig:8:5: [address] in _bar (test.o) | |
| 181 | \\source.zig:4:5: [address] in _foo (test.o) | |
| 182 | \\source.zig:16:5: [address] in _main.0 (test.o) | |
| 183 | \\ | |
| 184 | , | |
| 185 | // release-safe | |
| 186 | \\error: TheSkyIsFalling | |
| 187 | \\source.zig:12:5: [address] in _main (test.o) | |
| 188 | \\source.zig:8:5: [address] in _main (test.o) | |
| 189 | \\source.zig:4:5: [address] in _main (test.o) | |
| 190 | \\source.zig:16:5: [address] in _main (test.o) | |
| 191 | \\ | |
| 192 | , | |
| 193 | // release-fast | |
| 194 | \\error: TheSkyIsFalling | |
| 195 | \\ | |
| 196 | , | |
| 197 | // release-small | |
| 198 | \\error: TheSkyIsFalling | |
| 199 | \\ | |
| 200 | }, | |
| 201 | ); | |
| 202 | }, | |
| 203 | .windows => { | |
| 204 | cases.addCase( | |
| 205 | "return", | |
| 206 | source_return, | |
| 207 | [_][]const u8{ | |
| 208 | // debug | |
| 209 | \\error: TheSkyIsFalling | |
| 210 | \\source.zig:4:5: [address] in main (test.obj) | |
| 211 | \\ | |
| 212 | , | |
| 213 | // release-safe | |
| 214 | // --disabled-- results in segmenetation fault | |
| 215 | "", | |
| 216 | // release-fast | |
| 217 | \\error: TheSkyIsFalling | |
| 218 | \\ | |
| 219 | , | |
| 220 | // release-small | |
| 221 | \\error: TheSkyIsFalling | |
| 222 | \\ | |
| 223 | }, | |
| 224 | ); | |
| 225 | cases.addCase( | |
| 226 | "try return", | |
| 227 | source_try_return, | |
| 228 | [_][]const u8{ | |
| 229 | // debug | |
| 230 | \\error: TheSkyIsFalling | |
| 231 | \\source.zig:4:5: [address] in foo (test.obj) | |
| 232 | \\source.zig:8:5: [address] in main (test.obj) | |
| 233 | \\ | |
| 234 | , | |
| 235 | // release-safe | |
| 236 | // --disabled-- results in segmenetation fault | |
| 237 | "", | |
| 238 | // release-fast | |
| 239 | \\error: TheSkyIsFalling | |
| 240 | \\ | |
| 241 | , | |
| 242 | // release-small | |
| 243 | \\error: TheSkyIsFalling | |
| 244 | \\ | |
| 245 | }, | |
| 246 | ); | |
| 247 | cases.addCase( | |
| 248 | "try try return return", | |
| 249 | source_try_try_return_return, | |
| 250 | [_][]const u8{ | |
| 251 | // debug | |
| 252 | \\error: TheSkyIsFalling | |
| 253 | \\source.zig:12:5: [address] in make_error (test.obj) | |
| 254 | \\source.zig:8:5: [address] in bar (test.obj) | |
| 255 | \\source.zig:4:5: [address] in foo (test.obj) | |
| 256 | \\source.zig:16:5: [address] in main (test.obj) | |
| 257 | \\ | |
| 258 | , | |
| 259 | // release-safe | |
| 260 | // --disabled-- results in segmenetation fault | |
| 261 | "", | |
| 262 | // release-fast | |
| 263 | \\error: TheSkyIsFalling | |
| 264 | \\ | |
| 265 | , | |
| 266 | // release-small | |
| 267 | \\error: TheSkyIsFalling | |
| 268 | \\ | |
| 269 | }, | |
| 270 | ); | |
| 271 | }, | |
| 272 | else => {}, | |
| 273 | } | |
| 274 | } |
test/stage1/behavior.zig+1| ... | ... | @@ -30,6 +30,7 @@ comptime { |
| 30 | 30 | _ = @import("behavior/bugs/2114.zig"); |
| 31 | 31 | _ = @import("behavior/bugs/2346.zig"); |
| 32 | 32 | _ = @import("behavior/bugs/2578.zig"); |
| 33 | _ = @import("behavior/bugs/2692.zig"); | |
| 33 | 34 | _ = @import("behavior/bugs/3112.zig"); |
| 34 | 35 | _ = @import("behavior/bugs/394.zig"); |
| 35 | 36 | _ = @import("behavior/bugs/421.zig"); |
test/stage1/behavior/async_fn.zig+61| ... | ... | @@ -1031,3 +1031,64 @@ test "@typeOf an async function call of generic fn with error union type" { |
| 1031 | 1031 | }; |
| 1032 | 1032 | _ = async S.func(i32); |
| 1033 | 1033 | } |
| 1034 | ||
| 1035 | test "using @typeOf on a generic function call" { | |
| 1036 | const S = struct { | |
| 1037 | var global_frame: anyframe = undefined; | |
| 1038 | var global_ok = false; | |
| 1039 | ||
| 1040 | var buf: [100]u8 align(16) = undefined; | |
| 1041 | ||
| 1042 | fn amain(x: var) void { | |
| 1043 | if (x == 0) { | |
| 1044 | global_ok = true; | |
| 1045 | return; | |
| 1046 | } | |
| 1047 | suspend { | |
| 1048 | global_frame = @frame(); | |
| 1049 | } | |
| 1050 | const F = @typeOf(async amain(x - 1)); | |
| 1051 | const frame = @intToPtr(*F, @ptrToInt(&buf)); | |
| 1052 | return await @asyncCall(frame, {}, amain, x - 1); | |
| 1053 | } | |
| 1054 | }; | |
| 1055 | _ = async S.amain(u32(1)); | |
| 1056 | resume S.global_frame; | |
| 1057 | expect(S.global_ok); | |
| 1058 | } | |
| 1059 | ||
| 1060 | test "recursive call of await @asyncCall with struct return type" { | |
| 1061 | const S = struct { | |
| 1062 | var global_frame: anyframe = undefined; | |
| 1063 | var global_ok = false; | |
| 1064 | ||
| 1065 | var buf: [100]u8 align(16) = undefined; | |
| 1066 | ||
| 1067 | fn amain(x: var) Foo { | |
| 1068 | if (x == 0) { | |
| 1069 | global_ok = true; | |
| 1070 | return Foo{ .x = 1, .y = 2, .z = 3 }; | |
| 1071 | } | |
| 1072 | suspend { | |
| 1073 | global_frame = @frame(); | |
| 1074 | } | |
| 1075 | const F = @typeOf(async amain(x - 1)); | |
| 1076 | const frame = @intToPtr(*F, @ptrToInt(&buf)); | |
| 1077 | return await @asyncCall(frame, {}, amain, x - 1); | |
| 1078 | } | |
| 1079 | ||
| 1080 | const Foo = struct { | |
| 1081 | x: u64, | |
| 1082 | y: u64, | |
| 1083 | z: u64, | |
| 1084 | }; | |
| 1085 | }; | |
| 1086 | var res: S.Foo = undefined; | |
| 1087 | var frame: @typeOf(async S.amain(u32(1))) = undefined; | |
| 1088 | _ = @asyncCall(&frame, &res, S.amain, u32(1)); | |
| 1089 | resume S.global_frame; | |
| 1090 | expect(S.global_ok); | |
| 1091 | expect(res.x == 1); | |
| 1092 | expect(res.y == 2); | |
| 1093 | expect(res.z == 3); | |
| 1094 | } |
test/stage1/behavior/bugs/2692.zig created+6| ... | ... | @@ -0,0 +1,6 @@ |
| 1 | fn foo(a: []u8) void {} | |
| 2 | ||
| 3 | test "address of 0 length array" { | |
| 4 | var pt: [0]u8 = undefined; | |
| 5 | foo(&pt); | |
| 6 | } |
test/stage1/behavior/if.zig+11| ... | ... | @@ -63,3 +63,14 @@ test "labeled break inside comptime if inside runtime if" { |
| 63 | 63 | } |
| 64 | 64 | expect(answer == 42); |
| 65 | 65 | } |
| 66 | ||
| 67 | test "const result loc, runtime if cond, else unreachable" { | |
| 68 | const Num = enum { | |
| 69 | One, | |
| 70 | Two, | |
| 71 | }; | |
| 72 | ||
| 73 | var t = true; | |
| 74 | const x = if (t) Num.Two else unreachable; | |
| 75 | if (x != .Two) @compileError("bad"); | |
| 76 | } |
test/stage1/behavior/struct.zig+33| ... | ... | @@ -599,3 +599,36 @@ test "extern fn returns struct by value" { |
| 599 | 599 | S.entry(); |
| 600 | 600 | comptime S.entry(); |
| 601 | 601 | } |
| 602 | ||
| 603 | test "for loop over pointers to struct, getting field from struct pointer" { | |
| 604 | const S = struct { | |
| 605 | const Foo = struct { | |
| 606 | name: []const u8, | |
| 607 | }; | |
| 608 | ||
| 609 | var ok = true; | |
| 610 | ||
| 611 | fn eql(a: []const u8) bool { | |
| 612 | return true; | |
| 613 | } | |
| 614 | ||
| 615 | const ArrayList = struct { | |
| 616 | fn toSlice(self: *ArrayList) []*Foo { | |
| 617 | return ([*]*Foo)(undefined)[0..0]; | |
| 618 | } | |
| 619 | }; | |
| 620 | ||
| 621 | fn doTheTest() void { | |
| 622 | var objects: ArrayList = undefined; | |
| 623 | ||
| 624 | for (objects.toSlice()) |obj| { | |
| 625 | if (eql(obj.name)) { | |
| 626 | ok = false; | |
| 627 | } | |
| 628 | } | |
| 629 | ||
| 630 | expect(ok); | |
| 631 | } | |
| 632 | }; | |
| 633 | S.doTheTest(); | |
| 634 | } |
test/stage1/behavior/union.zig+10| ... | ... | @@ -457,3 +457,13 @@ test "@unionInit can modify a pointer value" { |
| 457 | 457 | value_ptr.* = @unionInit(UnionInitEnum, "Byte", 2); |
| 458 | 458 | expect(value.Byte == 2); |
| 459 | 459 | } |
| 460 | ||
| 461 | test "union no tag with struct member" { | |
| 462 | const Struct = struct {}; | |
| 463 | const Union = union { | |
| 464 | s: Struct, | |
| 465 | pub fn foo(self: *@This()) void {} | |
| 466 | }; | |
| 467 | var u = Union{ .s = Struct{} }; | |
| 468 | u.foo(); | |
| 469 | } |
test/tests.zig+210| ... | ... | @@ -16,6 +16,7 @@ const LibExeObjStep = build.LibExeObjStep; |
| 16 | 16 | |
| 17 | 17 | const compare_output = @import("compare_output.zig"); |
| 18 | 18 | const standalone = @import("standalone.zig"); |
| 19 | const stack_traces = @import("stack_traces.zig"); | |
| 19 | 20 | const compile_errors = @import("compile_errors.zig"); |
| 20 | 21 | const assemble_and_link = @import("assemble_and_link.zig"); |
| 21 | 22 | const runtime_safety = @import("runtime_safety.zig"); |
| ... | ... | @@ -57,6 +58,21 @@ pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8, modes: |
| 57 | 58 | return cases.step; |
| 58 | 59 | } |
| 59 | 60 | |
| 61 | pub fn addStackTraceTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { | |
| 62 | const cases = b.allocator.create(StackTracesContext) catch unreachable; | |
| 63 | cases.* = StackTracesContext{ | |
| 64 | .b = b, | |
| 65 | .step = b.step("test-stack-traces", "Run the stack trace tests"), | |
| 66 | .test_index = 0, | |
| 67 | .test_filter = test_filter, | |
| 68 | .modes = modes, | |
| 69 | }; | |
| 70 | ||
| 71 | stack_traces.addCases(cases); | |
| 72 | ||
| 73 | return cases.step; | |
| 74 | } | |
| 75 | ||
| 60 | 76 | pub fn addRuntimeSafetyTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { |
| 61 | 77 | const cases = b.allocator.create(CompareOutputContext) catch unreachable; |
| 62 | 78 | cases.* = CompareOutputContext{ |
| ... | ... | @@ -549,6 +565,200 @@ pub const CompareOutputContext = struct { |
| 549 | 565 | } |
| 550 | 566 | }; |
| 551 | 567 | |
| 568 | pub const StackTracesContext = struct { | |
| 569 | b: *build.Builder, | |
| 570 | step: *build.Step, | |
| 571 | test_index: usize, | |
| 572 | test_filter: ?[]const u8, | |
| 573 | modes: []const Mode, | |
| 574 | ||
| 575 | const Expect = [@typeInfo(Mode).Enum.fields.len][]const u8; | |
| 576 | ||
| 577 | pub fn addCase( | |
| 578 | self: *StackTracesContext, | |
| 579 | name: []const u8, | |
| 580 | source: []const u8, | |
| 581 | expect: Expect, | |
| 582 | ) void { | |
| 583 | const b = self.b; | |
| 584 | ||
| 585 | const source_pathname = fs.path.join( | |
| 586 | b.allocator, | |
| 587 | [_][]const u8{ b.cache_root, "source.zig" }, | |
| 588 | ) catch unreachable; | |
| 589 | ||
| 590 | for (self.modes) |mode| { | |
| 591 | const expect_for_mode = expect[@enumToInt(mode)]; | |
| 592 | if (expect_for_mode.len == 0) continue; | |
| 593 | ||
| 594 | const annotated_case_name = fmt.allocPrint(self.b.allocator, "{} {} ({})", "stack-trace", name, @tagName(mode)) catch unreachable; | |
| 595 | if (self.test_filter) |filter| { | |
| 596 | if (mem.indexOf(u8, annotated_case_name, filter) == null) continue; | |
| 597 | } | |
| 598 | ||
| 599 | const exe = b.addExecutable("test", source_pathname); | |
| 600 | exe.setBuildMode(mode); | |
| 601 | ||
| 602 | const write_source = b.addWriteFile(source_pathname, source); | |
| 603 | exe.step.dependOn(&write_source.step); | |
| 604 | ||
| 605 | const run_and_compare = RunAndCompareStep.create( | |
| 606 | self, | |
| 607 | exe, | |
| 608 | annotated_case_name, | |
| 609 | mode, | |
| 610 | expect_for_mode, | |
| 611 | ); | |
| 612 | ||
| 613 | self.step.dependOn(&run_and_compare.step); | |
| 614 | } | |
| 615 | } | |
| 616 | ||
| 617 | const RunAndCompareStep = struct { | |
| 618 | step: build.Step, | |
| 619 | context: *StackTracesContext, | |
| 620 | exe: *LibExeObjStep, | |
| 621 | name: []const u8, | |
| 622 | mode: Mode, | |
| 623 | expect_output: []const u8, | |
| 624 | test_index: usize, | |
| 625 | ||
| 626 | pub fn create( | |
| 627 | context: *StackTracesContext, | |
| 628 | exe: *LibExeObjStep, | |
| 629 | name: []const u8, | |
| 630 | mode: Mode, | |
| 631 | expect_output: []const u8, | |
| 632 | ) *RunAndCompareStep { | |
| 633 | const allocator = context.b.allocator; | |
| 634 | const ptr = allocator.create(RunAndCompareStep) catch unreachable; | |
| 635 | ptr.* = RunAndCompareStep{ | |
| 636 | .step = build.Step.init("StackTraceCompareOutputStep", allocator, make), | |
| 637 | .context = context, | |
| 638 | .exe = exe, | |
| 639 | .name = name, | |
| 640 | .mode = mode, | |
| 641 | .expect_output = expect_output, | |
| 642 | .test_index = context.test_index, | |
| 643 | }; | |
| 644 | ptr.step.dependOn(&exe.step); | |
| 645 | context.test_index += 1; | |
| 646 | return ptr; | |
| 647 | } | |
| 648 | ||
| 649 | fn make(step: *build.Step) !void { | |
| 650 | const self = @fieldParentPtr(RunAndCompareStep, "step", step); | |
| 651 | const b = self.context.b; | |
| 652 | ||
| 653 | const full_exe_path = self.exe.getOutputPath(); | |
| 654 | var args = ArrayList([]const u8).init(b.allocator); | |
| 655 | defer args.deinit(); | |
| 656 | args.append(full_exe_path) catch unreachable; | |
| 657 | ||
| 658 | warn("Test {}/{} {}...", self.test_index + 1, self.context.test_index, self.name); | |
| 659 | ||
| 660 | const child = std.ChildProcess.init(args.toSliceConst(), b.allocator) catch unreachable; | |
| 661 | defer child.deinit(); | |
| 662 | ||
| 663 | child.stdin_behavior = .Ignore; | |
| 664 | child.stdout_behavior = .Pipe; | |
| 665 | child.stderr_behavior = .Pipe; | |
| 666 | child.env_map = b.env_map; | |
| 667 | ||
| 668 | child.spawn() catch |err| debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err)); | |
| 669 | ||
| 670 | var stdout = Buffer.initNull(b.allocator); | |
| 671 | var stderr = Buffer.initNull(b.allocator); | |
| 672 | ||
| 673 | var stdout_file_in_stream = child.stdout.?.inStream(); | |
| 674 | var stderr_file_in_stream = child.stderr.?.inStream(); | |
| 675 | ||
| 676 | stdout_file_in_stream.stream.readAllBuffer(&stdout, max_stdout_size) catch unreachable; | |
| 677 | stderr_file_in_stream.stream.readAllBuffer(&stderr, max_stdout_size) catch unreachable; | |
| 678 | ||
| 679 | const term = child.wait() catch |err| { | |
| 680 | debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err)); | |
| 681 | }; | |
| 682 | ||
| 683 | switch (term) { | |
| 684 | .Exited => |code| { | |
| 685 | const expect_code: u32 = 1; | |
| 686 | if (code != expect_code) { | |
| 687 | warn("Process {} exited with error code {} but expected code {}\n", full_exe_path, code, expect_code); | |
| 688 | printInvocation(args.toSliceConst()); | |
| 689 | return error.TestFailed; | |
| 690 | } | |
| 691 | }, | |
| 692 | .Signal => |signum| { | |
| 693 | warn("Process {} terminated on signal {}\n", full_exe_path, signum); | |
| 694 | printInvocation(args.toSliceConst()); | |
| 695 | return error.TestFailed; | |
| 696 | }, | |
| 697 | .Stopped => |signum| { | |
| 698 | warn("Process {} stopped on signal {}\n", full_exe_path, signum); | |
| 699 | printInvocation(args.toSliceConst()); | |
| 700 | return error.TestFailed; | |
| 701 | }, | |
| 702 | .Unknown => |code| { | |
| 703 | warn("Process {} terminated unexpectedly with error code {}\n", full_exe_path, code); | |
| 704 | printInvocation(args.toSliceConst()); | |
| 705 | return error.TestFailed; | |
| 706 | }, | |
| 707 | } | |
| 708 | ||
| 709 | // process result | |
| 710 | // - keep only basename of source file path | |
| 711 | // - replace address with symbolic string | |
| 712 | // - skip empty lines | |
| 713 | const got: []const u8 = got_result: { | |
| 714 | var buf = try Buffer.initSize(b.allocator, 0); | |
| 715 | defer buf.deinit(); | |
| 716 | var bytes = stderr.toSliceConst(); | |
| 717 | if (bytes.len != 0 and bytes[bytes.len - 1] == '\n') bytes = bytes[0 .. bytes.len - 1]; | |
| 718 | var it = mem.separate(bytes, "\n"); | |
| 719 | process_lines: while (it.next()) |line| { | |
| 720 | if (line.len == 0) continue; | |
| 721 | const delims = [_][]const u8{ ":", ":", ":", " in " }; | |
| 722 | var marks = [_]usize{0} ** 4; | |
| 723 | // offset search past `[drive]:` on windows | |
| 724 | var pos: usize = if (builtin.os == .windows) 2 else 0; | |
| 725 | for (delims) |delim, i| { | |
| 726 | marks[i] = mem.indexOfPos(u8, line, pos, delim) orelse { | |
| 727 | try buf.append(line); | |
| 728 | try buf.append("\n"); | |
| 729 | continue :process_lines; | |
| 730 | }; | |
| 731 | pos = marks[i] + delim.len; | |
| 732 | } | |
| 733 | pos = mem.lastIndexOfScalar(u8, line[0..marks[0]], fs.path.sep) orelse { | |
| 734 | try buf.append(line); | |
| 735 | try buf.append("\n"); | |
| 736 | continue :process_lines; | |
| 737 | }; | |
| 738 | try buf.append(line[pos + 1 .. marks[2] + delims[2].len]); | |
| 739 | try buf.append(" [address]"); | |
| 740 | try buf.append(line[marks[3]..]); | |
| 741 | try buf.append("\n"); | |
| 742 | } | |
| 743 | break :got_result buf.toOwnedSlice(); | |
| 744 | }; | |
| 745 | ||
| 746 | if (!mem.eql(u8, self.expect_output, got)) { | |
| 747 | warn( | |
| 748 | \\ | |
| 749 | \\========= Expected this output: ========= | |
| 750 | \\{} | |
| 751 | \\================================================ | |
| 752 | \\{} | |
| 753 | \\ | |
| 754 | , self.expect_output, got); | |
| 755 | return error.TestFailed; | |
| 756 | } | |
| 757 | warn("OK\n"); | |
| 758 | } | |
| 759 | }; | |
| 760 | }; | |
| 761 | ||
| 552 | 762 | pub const CompileErrorContext = struct { |
| 553 | 763 | b: *build.Builder, |
| 554 | 764 | step: *build.Step, |