diff --git a/CMakeLists.txt b/CMakeLists.txt index d384bc1b3..59655757d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -600,7 +600,6 @@ set(ZIG_STD_FILES "sort.zig" "special/bootstrap.zig" "special/bootstrap_lib.zig" - "special/build_file_template.zig" "special/build_runner.zig" "special/builtin.zig" "special/compiler_rt/aulldiv.zig" @@ -618,22 +617,26 @@ set(ZIG_STD_FILES "special/compiler_rt/fixunstfdi.zig" "special/compiler_rt/fixunstfsi.zig" "special/compiler_rt/fixunstfti.zig" + "special/compiler_rt/floattidf.zig" + "special/compiler_rt/floattisf.zig" + "special/compiler_rt/floattitf.zig" "special/compiler_rt/floatunditf.zig" "special/compiler_rt/floatunsitf.zig" "special/compiler_rt/floatuntidf.zig" "special/compiler_rt/floatuntisf.zig" "special/compiler_rt/floatuntitf.zig" - "special/compiler_rt/floattidf.zig" - "special/compiler_rt/floattisf.zig" - "special/compiler_rt/floattitf.zig" - "special/compiler_rt/muloti4.zig" "special/compiler_rt/index.zig" + "special/compiler_rt/muloti4.zig" "special/compiler_rt/truncXfYf2.zig" "special/compiler_rt/udivmod.zig" "special/compiler_rt/udivmoddi4.zig" "special/compiler_rt/udivmodti4.zig" "special/compiler_rt/udivti3.zig" "special/compiler_rt/umodti3.zig" + "special/init-exe/build.zig" + "special/init-exe/src/main.zig" + "special/init-lib/build.zig" + "special/init-lib/src/main.zig" "special/panic.zig" "special/test_runner.zig" "unicode.zig" @@ -796,6 +799,9 @@ if(MSVC) set(EXE_CFLAGS "${EXE_CFLAGS}") else() set(EXE_CFLAGS "${EXE_CFLAGS} -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D_GNU_SOURCE -fno-exceptions -fno-rtti -Werror=strict-prototypes -Werror=old-style-definition -Werror=type-limits -Wno-missing-braces") + if(MINGW) + set(EXE_CFLAGS "${EXE_CFLAGS} -D__USE_MINGW_ANSI_STDIO -Wno-pedantic-ms-format") + endif() endif() set(BLAKE_CFLAGS "-std=c99") diff --git a/build.zig b/build.zig index 0bb4808dc..bc9cd4c1c 100644 --- a/build.zig +++ b/build.zig @@ -112,6 +112,7 @@ pub fn build(b: *Builder) !void { test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes)); test_step.dependOn(tests.addBuildExampleTests(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)); diff --git a/doc/langref.html.in b/doc/langref.html.in index f5b92873e..9bd11b823 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5877,7 +5877,7 @@ fn add(a: i32, b: i32) i32 { {#header_open|@OpaqueType#}
{#syntax#}@OpaqueType() type{#endsyntax#}

- Creates a new type with an unknown size and alignment. + Creates a new type with an unknown (but non-zero) size and alignment.

This is typically used for type safety when interacting with C code that does not expose struct details. diff --git a/example/hello_world/hello_windows.zig b/example/hello_world/hello_windows.zig index f55db2ede..8016c3c49 100644 --- a/example/hello_world/hello_windows.zig +++ b/example/hello_world/hello_windows.zig @@ -1,5 +1,7 @@ use @import("std").os.windows; +extern "user32" stdcallcc fn MessageBoxA(hWnd: ?HANDLE, lpText: ?LPCTSTR, lpCaption: ?LPCTSTR, uType: UINT) c_int; + export fn WinMain(hInstance: HINSTANCE, hPrevInstance: HINSTANCE, lpCmdLine: PWSTR, nCmdShow: INT) INT { _ = MessageBoxA(null, c"hello", c"title", 0); return 0; diff --git a/src/analyze.cpp b/src/analyze.cpp index c9ae86539..328eda786 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1470,7 +1470,8 @@ static bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) { case ZigTypeIdArray: return type_allowed_in_extern(g, type_entry->data.array.child_type); case ZigTypeIdFn: - return type_entry->data.fn.fn_type_id.cc == CallingConventionC; + return type_entry->data.fn.fn_type_id.cc == CallingConventionC || + type_entry->data.fn.fn_type_id.cc == CallingConventionStdcall; case ZigTypeIdPointer: if (type_size(g, type_entry) == 0) return false; @@ -3992,9 +3993,10 @@ uint32_t get_ptr_align(CodeGen *g, ZigType *type) { return (ptr_type->data.pointer.explicit_alignment == 0) ? get_abi_alignment(g, ptr_type->data.pointer.child_type) : ptr_type->data.pointer.explicit_alignment; } else if (ptr_type->id == ZigTypeIdFn) { - return (ptr_type->data.fn.fn_type_id.alignment == 0) ? - LLVMABIAlignmentOfType(g->target_data_ref, ptr_type->data.fn.raw_type_ref) : - ptr_type->data.fn.fn_type_id.alignment; + // I tried making this use LLVMABIAlignmentOfType but it trips this assertion in LLVM: + // "Cannot getTypeInfo() on a type that is unsized!" + // when getting the alignment of `?extern fn() void`. + return (ptr_type->data.fn.fn_type_id.alignment == 0) ? 1 : ptr_type->data.fn.fn_type_id.alignment; } else if (ptr_type->id == ZigTypeIdPromise) { return get_coro_frame_align_bytes(g); } else { diff --git a/src/codegen.cpp b/src/codegen.cpp index cad3694fe..91e7c8dde 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1662,6 +1662,22 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z if (actual_type->id == ZigTypeIdFloat) { return LLVMBuildFPTrunc(g->builder, expr_val, wanted_type->type_ref, ""); } else if (actual_type->id == ZigTypeIdInt) { + if (wanted_bits == 0) { + if (!want_runtime_safety) + return nullptr; + + LLVMValueRef zero = LLVMConstNull(actual_type->type_ref); + LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, expr_val, zero, ""); + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenOk"); + LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenFail"); + LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); + + LLVMPositionBuilderAtEnd(g->builder, fail_block); + gen_safety_crash(g, PanicMsgIdCastTruncatedData); + + LLVMPositionBuilderAtEnd(g->builder, ok_block); + return nullptr; + } LLVMValueRef trunc_val = LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, ""); if (!want_runtime_safety) { return trunc_val; diff --git a/src/compiler.cpp b/src/compiler.cpp index dd02b541d..0d4dff5d5 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -5,6 +5,9 @@ static Buf saved_compiler_id = BUF_INIT; static Buf saved_app_data_dir = BUF_INIT; static Buf saved_stage1_path = BUF_INIT; +static Buf saved_lib_dir = BUF_INIT; +static Buf saved_special_dir = BUF_INIT; +static Buf saved_std_dir = BUF_INIT; Buf *get_stage1_cache_path() { if (saved_stage1_path.list.length != 0) { @@ -64,3 +67,101 @@ Error get_compiler_id(Buf **result) { return ErrorNone; } + +static bool test_zig_install_prefix(Buf *test_path, Buf *out_zig_lib_dir) { + Buf lib_buf = BUF_INIT; + buf_init_from_str(&lib_buf, "lib"); + + Buf zig_buf = BUF_INIT; + buf_init_from_str(&zig_buf, "zig"); + + Buf std_buf = BUF_INIT; + buf_init_from_str(&std_buf, "std"); + + Buf index_zig_buf = BUF_INIT; + buf_init_from_str(&index_zig_buf, "index.zig"); + + Buf test_lib_dir = BUF_INIT; + Buf test_zig_dir = BUF_INIT; + Buf test_std_dir = BUF_INIT; + Buf test_index_file = BUF_INIT; + + os_path_join(test_path, &lib_buf, &test_lib_dir); + os_path_join(&test_lib_dir, &zig_buf, &test_zig_dir); + os_path_join(&test_zig_dir, &std_buf, &test_std_dir); + os_path_join(&test_std_dir, &index_zig_buf, &test_index_file); + + int err; + bool exists; + if ((err = os_file_exists(&test_index_file, &exists))) { + exists = false; + } + if (exists) { + buf_init_from_buf(out_zig_lib_dir, &test_zig_dir); + return true; + } + return false; +} + +static int find_zig_lib_dir(Buf *out_path) { + int err; + + Buf self_exe_path = BUF_INIT; + buf_resize(&self_exe_path, 0); + if (!(err = os_self_exe_path(&self_exe_path))) { + Buf *cur_path = &self_exe_path; + + for (;;) { + Buf *test_dir = buf_alloc(); + os_path_dirname(cur_path, test_dir); + + if (buf_eql_buf(test_dir, cur_path)) { + break; + } + + if (test_zig_install_prefix(test_dir, out_path)) { + return 0; + } + + cur_path = test_dir; + } + } + + return ErrorFileNotFound; +} + +Buf *get_zig_lib_dir(void) { + if (saved_lib_dir.list.length != 0) { + return &saved_lib_dir; + } + buf_resize(&saved_lib_dir, 0); + + int err; + if ((err = find_zig_lib_dir(&saved_lib_dir))) { + fprintf(stderr, "Unable to find zig lib directory\n"); + exit(EXIT_FAILURE); + } + return &saved_lib_dir; +} + +Buf *get_zig_std_dir() { + if (saved_std_dir.list.length != 0) { + return &saved_std_dir; + } + buf_resize(&saved_std_dir, 0); + + os_path_join(get_zig_lib_dir(), buf_create_from_str("std"), &saved_std_dir); + + return &saved_std_dir; +} + +Buf *get_zig_special_dir() { + if (saved_special_dir.list.length != 0) { + return &saved_special_dir; + } + buf_resize(&saved_special_dir, 0); + + os_path_join(get_zig_std_dir(), buf_sprintf("special"), &saved_special_dir); + + return &saved_special_dir; +} diff --git a/src/compiler.hpp b/src/compiler.hpp index b95e4ceda..ffdd1cefb 100644 --- a/src/compiler.hpp +++ b/src/compiler.hpp @@ -14,4 +14,8 @@ Buf *get_stage1_cache_path(); Error get_compiler_id(Buf **result); +Buf *get_zig_lib_dir(); +Buf *get_zig_special_dir(); +Buf *get_zig_std_dir(); + #endif diff --git a/src/ir.cpp b/src/ir.cpp index ce044aa0f..350459db2 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -10015,21 +10015,25 @@ static IrInstruction *ir_analyze_cast_ref(IrAnalyze *ira, IrInstruction *source_ if (value->id == IrInstructionIdLoadPtr) { IrInstructionLoadPtr *load_ptr_inst = (IrInstructionLoadPtr *)value; - return load_ptr_inst->ptr; - } else { - IrInstruction *new_instruction = ir_build_ref(&ira->new_irb, source_instr->scope, - source_instr->source_node, value, true, false); - new_instruction->value.type = wanted_type; - - ZigType *child_type = wanted_type->data.pointer.child_type; - if (type_has_bits(child_type)) { - ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec); - assert(fn_entry); - fn_entry->alloca_list.append(new_instruction); - } - ir_add_alloca(ira, new_instruction, child_type); - return new_instruction; + ConstCastOnly const_cast_result = types_match_const_cast_only(ira, wanted_type, + load_ptr_inst->ptr->value.type, source_instr->source_node, false); + if (const_cast_result.id == ConstCastResultIdInvalid) + return ira->codegen->invalid_instruction; + if (const_cast_result.id == ConstCastResultIdOk) + return load_ptr_inst->ptr; } + IrInstruction *new_instruction = ir_build_ref(&ira->new_irb, source_instr->scope, + source_instr->source_node, value, true, false); + new_instruction->value.type = wanted_type; + + ZigType *child_type = wanted_type->data.pointer.child_type; + if (type_has_bits(child_type)) { + ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec); + assert(fn_entry); + fn_entry->alloca_list.append(new_instruction); + } + ir_add_alloca(ira, new_instruction, child_type); + return new_instruction; } static IrInstruction *ir_analyze_null_to_maybe(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, ZigType *wanted_type) { @@ -11057,7 +11061,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } } - // enum to &const union which has the enum as the tag type + // enum to *const union which has the enum as the tag type if (actual_type->id == ZigTypeIdEnum && wanted_type->id == ZigTypeIdPointer) { ZigType *union_type = wanted_type->data.pointer.child_type; if (union_type->data.unionation.decl_node->data.container_decl.auto_enum || @@ -11187,6 +11191,13 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc } } } + // dereferencing a *u0 is comptime known to be 0 + if (child_type->id == ZigTypeIdInt && child_type->data.integral.bit_count == 0) { + IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope, + source_instruction->source_node, child_type); + init_const_unsigned_negative(&result->value, child_type, 0, false); + return result; + } // TODO if the instruction is a const ref instruction we can skip it IrInstruction *load_ptr_instruction = ir_build_load_ptr(&ira->new_irb, source_instruction->scope, source_instruction->source_node, ptr); @@ -11521,7 +11532,13 @@ static bool optional_value_is_null(ConstExprValue *val) { static ZigType *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { Error err; IrInstruction *op1 = bin_op_instruction->op1->other; + if (type_is_invalid(op1->value.type)) + return ira->codegen->builtin_types.entry_invalid; + IrInstruction *op2 = bin_op_instruction->op2->other; + if (type_is_invalid(op2->value.type)) + return ira->codegen->builtin_types.entry_invalid; + AstNode *source_node = bin_op_instruction->base.source_node; IrBinOp op_id = bin_op_instruction->op_id; @@ -11564,6 +11581,9 @@ static ZigType *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op ir_link_new_instruction(is_non_null, &bin_op_instruction->base); } return ira->codegen->builtin_types.entry_bool; + } else if (op1->value.type->id == ZigTypeIdNull || op2->value.type->id == ZigTypeIdNull) { + ir_add_error_node(ira, source_node, buf_sprintf("comparison against null can only be done with optionals")); + return ira->codegen->builtin_types.entry_invalid; } if (op1->value.type->id == ZigTypeIdErrorSet && op2->value.type->id == ZigTypeIdErrorSet) { @@ -12063,6 +12083,12 @@ static ZigType *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *bin_op_ ir_add_error(ira, &bin_op_instruction->base, buf_sprintf("LHS of shift must be an integer type, or RHS must be compile-time known")); return ira->codegen->builtin_types.entry_invalid; + } else if (instr_is_comptime(casted_op2) && bigint_cmp_zero(&casted_op2->value.data.x_bigint) == CmpEQ) { + IrInstruction *result = ir_build_cast(&ira->new_irb, bin_op_instruction->base.scope, + bin_op_instruction->base.source_node, op1->value.type, op1, CastOpNoop); + result->value.type = op1->value.type; + ir_link_new_instruction(result, &bin_op_instruction->base); + return result->value.type; } ir_build_bin_op_from(&ira->new_irb, &bin_op_instruction->base, op_id, @@ -18165,17 +18191,18 @@ static ZigType *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstructionE &source_dir_path, rel_file_path, }; - Buf file_path = os_path_resolve(resolve_paths, 2); + Buf *file_path = buf_alloc(); + *file_path = os_path_resolve(resolve_paths, 2); // load from file system into const expr Buf *file_contents = buf_alloc(); int err; - if ((err = file_fetch(ira->codegen, &file_path, file_contents))) { + if ((err = file_fetch(ira->codegen, file_path, file_contents))) { if (err == ErrorFileNotFound) { - ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path))); + ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(file_path))); return ira->codegen->builtin_types.entry_invalid; } else { - ir_add_error(ira, instruction->name, buf_sprintf("unable to open '%s': %s", buf_ptr(&file_path), err_str(err))); + ir_add_error(ira, instruction->name, buf_sprintf("unable to open '%s': %s", buf_ptr(file_path), err_str(err))); return ira->codegen->builtin_types.entry_invalid; } } @@ -18494,6 +18521,9 @@ static ZigType *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstructionF src_ptr_align = get_abi_alignment(ira->codegen, target->value.type); } + if ((err = type_resolve(ira->codegen, dest_child_type, ResolveStatusSizeKnown))) + return ira->codegen->builtin_types.entry_invalid; + ZigType *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, dest_child_type, src_ptr_const, src_ptr_volatile, PtrLenUnknown, src_ptr_align, 0, 0); @@ -20174,11 +20204,19 @@ static ZigType *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtr instruction->base.source_node, nullptr, ptr); casted_ptr->value.type = dest_type; + if (type_has_bits(dest_type) && !type_has_bits(src_type)) { + ErrorMsg *msg = ir_add_error(ira, &instruction->base, + buf_sprintf("'%s' and '%s' do not have the same in-memory representation", + buf_ptr(&src_type->name), buf_ptr(&dest_type->name))); + add_error_note(ira->codegen, msg, ptr->source_node, + buf_sprintf("'%s' has no in-memory bits", buf_ptr(&src_type->name))); + add_error_note(ira->codegen, msg, dest_type_value->source_node, + buf_sprintf("'%s' has in-memory bits", buf_ptr(&dest_type->name))); + return ira->codegen->builtin_types.entry_invalid; + } + // Keep the bigger alignment, it can only help- // unless the target is zero bits. - if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->builtin_types.entry_invalid; - IrInstruction *result; if (src_align_bytes > dest_align_bytes && type_has_bits(dest_type)) { result = ir_align_cast(ira, casted_ptr, src_align_bytes, false); @@ -20216,6 +20254,11 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue bigint_write_twos_complement(&val->data.x_bigint, buf, val->type->data.integral.bit_count, codegen->is_big_endian); return; + case ZigTypeIdEnum: + bigint_write_twos_complement(&val->data.x_enum_tag, buf, + val->type->data.enumeration.tag_int_type->data.integral.bit_count, + codegen->is_big_endian); + return; case ZigTypeIdFloat: float_write_ieee597(val, buf, codegen->is_big_endian); return; @@ -20247,8 +20290,6 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue zig_panic("TODO buf_write_value_bytes error union"); case ZigTypeIdErrorSet: zig_panic("TODO buf_write_value_bytes pure error type"); - case ZigTypeIdEnum: - zig_panic("TODO buf_write_value_bytes enum type"); case ZigTypeIdFn: zig_panic("TODO buf_write_value_bytes fn type"); case ZigTypeIdUnion: diff --git a/src/main.cpp b/src/main.cpp index bf6c14297..95fba8d59 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -25,6 +25,8 @@ static int usage(const char *arg0) { " build-obj [source] create object from source or assembly\n" " builtin show the source code of that @import(\"builtin\")\n" " id print the base64-encoded compiler id\n" + " init-exe initialize a `zig build` application in the cwd\n" + " init-lib initialize a `zig build` library in the cwd\n" " run [source] create executable and run immediately\n" " translate-c [source] convert c code to zig code\n" " targets list available compilation targets\n" @@ -34,7 +36,7 @@ static int usage(const char *arg0) { "Compile Options:\n" " --assembly [source] add assembly file to build\n" " --cache-dir [path] override the cache directory\n" - " --cache [auto|off|on] build to the global cache and print output path to stdout\n" + " --cache [auto|off|on] build in global cache, print out paths to stdout\n" " --color [auto|off|on] enable or disable colored error messages\n" " --emit [asm|bin|llvm-ir] emit a specific file format as compilation output\n" " -ftime-report print timing diagnostics\n" @@ -42,7 +44,7 @@ static int usage(const char *arg0) { " --name [name] override output name\n" " --output [file] override destination path\n" " --output-h [file] override generated header file path\n" - " --pkg-begin [name] [path] make package available to import and push current pkg\n" + " --pkg-begin [name] [path] make pkg available to import and push current pkg\n" " --pkg-end pop current pkg\n" " --release-fast build with optimizations on and safety off\n" " --release-safe build with optimizations on and safety on\n" @@ -52,17 +54,16 @@ static int usage(const char *arg0) { " --target-arch [name] specify target architecture\n" " --target-environ [name] specify target environment\n" " --target-os [name] specify target operating system\n" - " --verbose-tokenize turn on compiler debug output for tokenization\n" - " --verbose-ast turn on compiler debug output for parsing into an AST\n" - " --verbose-link turn on compiler debug output for linking\n" - " --verbose-ir turn on compiler debug output for Zig IR\n" - " --verbose-llvm-ir turn on compiler debug output for LLVM IR\n" - " --verbose-cimport turn on compiler debug output for C imports\n" + " --verbose-tokenize enable compiler debug output for tokenization\n" + " --verbose-ast enable compiler debug output for AST parsing\n" + " --verbose-link enable compiler debug output for linking\n" + " --verbose-ir enable compiler debug output for Zig IR\n" + " --verbose-llvm-ir enable compiler debug output for LLVM IR\n" + " --verbose-cimport enable compiler debug output for C imports\n" " -dirafter [dir] same as -isystem but do it last\n" " -isystem [dir] add additional search path for other .h files\n" - " -mllvm [arg] additional arguments to forward to LLVM's option processing\n" + " -mllvm [arg] forward an arg to LLVM's option processing\n" "Link Options:\n" - " --ar-path [path] set the path to ar\n" " --dynamic-linker [path] set the path to ld.so\n" " --each-lib-rpath add rpath for each used dynamic library\n" " --libc-lib-dir [path] directory where libc crt1.o resides\n" @@ -142,78 +143,6 @@ static int print_target_list(FILE *f) { return EXIT_SUCCESS; } -static bool test_zig_install_prefix(Buf *test_path, Buf *out_zig_lib_dir) { - Buf lib_buf = BUF_INIT; - buf_init_from_str(&lib_buf, "lib"); - - Buf zig_buf = BUF_INIT; - buf_init_from_str(&zig_buf, "zig"); - - Buf std_buf = BUF_INIT; - buf_init_from_str(&std_buf, "std"); - - Buf index_zig_buf = BUF_INIT; - buf_init_from_str(&index_zig_buf, "index.zig"); - - Buf test_lib_dir = BUF_INIT; - Buf test_zig_dir = BUF_INIT; - Buf test_std_dir = BUF_INIT; - Buf test_index_file = BUF_INIT; - - os_path_join(test_path, &lib_buf, &test_lib_dir); - os_path_join(&test_lib_dir, &zig_buf, &test_zig_dir); - os_path_join(&test_zig_dir, &std_buf, &test_std_dir); - os_path_join(&test_std_dir, &index_zig_buf, &test_index_file); - - int err; - bool exists; - if ((err = os_file_exists(&test_index_file, &exists))) { - exists = false; - } - if (exists) { - buf_init_from_buf(out_zig_lib_dir, &test_zig_dir); - return true; - } - return false; -} - -static int find_zig_lib_dir(Buf *out_path) { - int err; - - Buf self_exe_path = BUF_INIT; - buf_resize(&self_exe_path, 0); - if (!(err = os_self_exe_path(&self_exe_path))) { - Buf *cur_path = &self_exe_path; - - for (;;) { - Buf *test_dir = buf_alloc(); - os_path_dirname(cur_path, test_dir); - - if (buf_eql_buf(test_dir, cur_path)) { - break; - } - - if (test_zig_install_prefix(test_dir, out_path)) { - return 0; - } - - cur_path = test_dir; - } - } - - return ErrorFileNotFound; -} - -static Buf *resolve_zig_lib_dir(void) { - int err; - Buf *result = buf_alloc(); - if ((err = find_zig_lib_dir(result))) { - fprintf(stderr, "Unable to find zig lib directory\n"); - exit(EXIT_FAILURE); - } - return result; -} - enum Cmd { CmdInvalid, CmdBuild, @@ -277,6 +206,9 @@ static bool get_cache_opt(CacheOpt opt, bool default_value) { } int main(int argc, char **argv) { + char *arg0 = argv[0]; + Error err; + if (argc == 2 && strcmp(argv[1], "BUILD_INFO") == 0) { printf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", ZIG_CMAKE_BINARY_DIR, @@ -290,8 +222,10 @@ int main(int argc, char **argv) { return 0; } + // Must be before all os.hpp function calls. + os_init(); + if (argc == 2 && strcmp(argv[1], "id") == 0) { - Error err; Buf *compiler_id; if ((err = get_compiler_id(&compiler_id))) { fprintf(stderr, "Unable to determine compiler id: %s\n", err_str(err)); @@ -301,9 +235,97 @@ int main(int argc, char **argv) { return EXIT_SUCCESS; } - os_init(); + enum InitKind { + InitKindNone, + InitKindExe, + InitKindLib, + }; + InitKind init_kind = InitKindNone; + if (argc >= 2) { + const char *init_cmd = argv[1]; + if (strcmp(init_cmd, "init-exe") == 0) { + init_kind = InitKindExe; + } else if (strcmp(init_cmd, "init-lib") == 0) { + init_kind = InitKindLib; + } + if (init_kind != InitKindNone) { + if (argc >= 3) { + fprintf(stderr, "Unexpected extra argument: %s\n", argv[2]); + return usage(arg0); + } + Buf *cmd_template_path = buf_alloc(); + os_path_join(get_zig_special_dir(), buf_create_from_str(init_cmd), cmd_template_path); + Buf *build_zig_path = buf_alloc(); + os_path_join(cmd_template_path, buf_create_from_str("build.zig"), build_zig_path); + Buf *src_dir_path = buf_alloc(); + os_path_join(cmd_template_path, buf_create_from_str("src"), src_dir_path); + Buf *main_zig_path = buf_alloc(); + os_path_join(src_dir_path, buf_create_from_str("main.zig"), main_zig_path); + + Buf *cwd = buf_alloc(); + if ((err = os_get_cwd(cwd))) { + fprintf(stderr, "Unable to get cwd: %s\n", err_str(err)); + return EXIT_FAILURE; + } + Buf *cwd_basename = buf_alloc(); + os_path_split(cwd, nullptr, cwd_basename); + + Buf *build_zig_contents = buf_alloc(); + if ((err = os_fetch_file_path(build_zig_path, build_zig_contents, false))) { + fprintf(stderr, "Unable to read %s: %s\n", buf_ptr(build_zig_path), err_str(err)); + return EXIT_FAILURE; + } + Buf *modified_build_zig_contents = buf_alloc(); + for (size_t i = 0; i < buf_len(build_zig_contents); i += 1) { + char c = buf_ptr(build_zig_contents)[i]; + if (c == '$') { + buf_append_buf(modified_build_zig_contents, cwd_basename); + } else { + buf_append_char(modified_build_zig_contents, c); + } + } + + Buf *main_zig_contents = buf_alloc(); + if ((err = os_fetch_file_path(main_zig_path, main_zig_contents, false))) { + fprintf(stderr, "Unable to read %s: %s\n", buf_ptr(main_zig_path), err_str(err)); + return EXIT_FAILURE; + } + + Buf *out_build_zig_path = buf_create_from_str("build.zig"); + Buf *out_src_dir_path = buf_create_from_str("src"); + Buf *out_main_zig_path = buf_alloc(); + os_path_join(out_src_dir_path, buf_create_from_str("main.zig"), out_main_zig_path); + + bool already_exists; + if ((err = os_file_exists(out_build_zig_path, &already_exists))) { + fprintf(stderr, "Unable test existence of %s: %s\n", buf_ptr(out_build_zig_path), err_str(err)); + return EXIT_FAILURE; + } + if (already_exists) { + fprintf(stderr, "This file would be overwritten: %s\n", buf_ptr(out_build_zig_path)); + return EXIT_FAILURE; + } + + if ((err = os_make_dir(out_src_dir_path))) { + fprintf(stderr, "Unable to make directory: %s: %s\n", buf_ptr(out_src_dir_path), err_str(err)); + return EXIT_FAILURE; + } + os_write_file(out_build_zig_path, modified_build_zig_contents); + os_write_file(out_main_zig_path, main_zig_contents); + fprintf(stderr, "Created %s\n", buf_ptr(out_build_zig_path)); + fprintf(stderr, "Created %s\n", buf_ptr(out_main_zig_path)); + if (init_kind == InitKindExe) { + fprintf(stderr, "\nNext, try `zig build --help` or `zig build run`\n"); + } else if (init_kind == InitKindLib) { + fprintf(stderr, "\nNext, try `zig build --help` or `zig build test`\n"); + } else { + zig_unreachable(); + } + + return EXIT_SUCCESS; + } + } - char *arg0 = argv[0]; Cmd cmd = CmdInvalid; EmitFileType emit_file_type = EmitFileTypeBinary; const char *in_file = nullptr; @@ -333,7 +355,6 @@ int main(int argc, char **argv) { ZigList link_libs = {0}; ZigList forbidden_link_libs = {0}; ZigList frameworks = {0}; - int err; const char *target_arch = nullptr; const char *target_os = nullptr; const char *target_environ = nullptr; @@ -364,7 +385,6 @@ int main(int argc, char **argv) { const char *zig_exe_path = arg0; const char *build_file = "build.zig"; bool asked_for_help = false; - bool asked_to_init = false; init_all_targets(); @@ -376,9 +396,6 @@ int main(int argc, char **argv) { if (strcmp(argv[i], "--help") == 0) { asked_for_help = true; args.append(argv[i]); - } else if (strcmp(argv[i], "--init") == 0) { - asked_to_init = true; - args.append(argv[i]); } else if (i + 1 < argc && strcmp(argv[i], "--build-file") == 0) { build_file = argv[i + 1]; i += 1; @@ -390,18 +407,10 @@ int main(int argc, char **argv) { } } - Buf *zig_lib_dir_buf = resolve_zig_lib_dir(); - - Buf *zig_std_dir = buf_alloc(); - os_path_join(zig_lib_dir_buf, buf_create_from_str("std"), zig_std_dir); - - Buf *special_dir = buf_alloc(); - os_path_join(zig_std_dir, buf_sprintf("special"), special_dir); - Buf *build_runner_path = buf_alloc(); - os_path_join(special_dir, buf_create_from_str("build_runner.zig"), build_runner_path); + os_path_join(get_zig_special_dir(), buf_create_from_str("build_runner.zig"), build_runner_path); - CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe, BuildModeDebug, zig_lib_dir_buf); + CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe, BuildModeDebug, get_zig_lib_dir()); g->enable_time_report = timing_info; buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name); codegen_set_out_name(g, buf_create_from_str("build")); @@ -437,7 +446,6 @@ int main(int argc, char **argv) { "\n" "General Options:\n" " --help Print this help and exit\n" - " --init Generate a build.zig template\n" " --build-file [file] Override path to build.zig\n" " --cache-dir [path] Override path to cache directory\n" " --verbose Print commands before executing them\n" @@ -463,22 +471,11 @@ int main(int argc, char **argv) { "\n" , zig_exe_path); return EXIT_SUCCESS; - } else if (asked_to_init) { - Buf *build_template_path = buf_alloc(); - os_path_join(special_dir, buf_create_from_str("build_file_template.zig"), build_template_path); - - if ((err = os_copy_file(build_template_path, &build_file_abs))) { - fprintf(stderr, "Unable to write build.zig template: %s\n", err_str(err)); - return EXIT_FAILURE; - } else { - fprintf(stderr, "Wrote build.zig template\n"); - return EXIT_SUCCESS; - } } fprintf(stderr, "No 'build.zig' file found.\n" - "Initialize a 'build.zig' template file with `zig build --init`,\n" + "Initialize a 'build.zig' template file with `zig init-lib` or `zig init-exe`,\n" "or build an executable directly with `zig build-exe $FILENAME.zig`.\n" "See: `zig build --help` or `zig help` for more options.\n" ); @@ -773,8 +770,7 @@ int main(int argc, char **argv) { switch (cmd) { case CmdBuiltin: { - Buf *zig_lib_dir_buf = resolve_zig_lib_dir(); - CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, zig_lib_dir_buf); + CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, get_zig_lib_dir()); Buf *builtin_source = codegen_generate_builtin_source(g); if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) { fprintf(stderr, "unable to write to stdout: %s\n", strerror(ferror(stdout))); @@ -832,9 +828,7 @@ int main(int argc, char **argv) { if (cmd == CmdRun && buf_out_name == nullptr) { buf_out_name = buf_create_from_str("run"); } - Buf *zig_lib_dir_buf = resolve_zig_lib_dir(); - - CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, zig_lib_dir_buf); + CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, get_zig_lib_dir()); g->enable_time_report = timing_info; buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name); codegen_set_out_name(g, buf_out_name); diff --git a/src/os.cpp b/src/os.cpp index 6e46b96e4..b68242988 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -23,6 +23,14 @@ #define WIN32_LEAN_AND_MEAN #endif +#if !defined(_WIN32_WINNT) +#define _WIN32_WINNT 0x600 +#endif + +#if !defined(NTDDI_VERSION) +#define NTDDI_VERSION 0x06000000 +#endif + #include #include #include @@ -1091,14 +1099,14 @@ Error os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) { return result; } -int os_get_cwd(Buf *out_cwd) { +Error os_get_cwd(Buf *out_cwd) { #if defined(ZIG_OS_WINDOWS) char buf[4096]; if (GetCurrentDirectory(4096, buf) == 0) { zig_panic("GetCurrentDirectory failed"); } buf_init_from_str(out_cwd, buf); - return 0; + return ErrorNone; #elif defined(ZIG_OS_POSIX) char buf[PATH_MAX]; char *res = getcwd(buf, PATH_MAX); @@ -1106,7 +1114,7 @@ int os_get_cwd(Buf *out_cwd) { zig_panic("unable to get cwd: %s", strerror(errno)); } buf_init_from_str(out_cwd, res); - return 0; + return ErrorNone; #else #error "missing os_get_cwd implementation" #endif @@ -1634,16 +1642,16 @@ static Optional Utf16LeIterator_nextCodepoint(Utf16LeIterator *it) { if (it->bytes[it->i] == 0 && it->bytes[it->i + 1] == 0) return {}; uint32_t c0 = ((uint32_t)it->bytes[it->i]) | (((uint32_t)it->bytes[it->i + 1]) << 8); - if (c0 & ~((uint32_t)0x03ff) == 0xd800) { + if ((c0 & ~((uint32_t)0x03ff)) == 0xd800) { // surrogate pair it->i += 2; assert(it->bytes[it->i] != 0 || it->bytes[it->i + 1] != 0); uint32_t c1 = ((uint32_t)it->bytes[it->i]) | (((uint32_t)it->bytes[it->i + 1]) << 8); - assert(c1 & ~((uint32_t)0x03ff) == 0xdc00); + assert((c1 & ~((uint32_t)0x03ff)) == 0xdc00); it->i += 2; return Optional::some(0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff))); } else { - assert(c0 & ~((uint32_t)0x03ff) != 0xdc00); + assert((c0 & ~((uint32_t)0x03ff)) != 0xdc00); it->i += 2; return Optional::some(c0); } @@ -1714,7 +1722,6 @@ static void utf16le_ptr_to_utf8(Buf *out, WCHAR *utf16le) { // Ported from std.os.getAppDataDir Error os_get_app_data_dir(Buf *out_path, const char *appname) { #if defined(ZIG_OS_WINDOWS) - Error err; WCHAR *dir_path_ptr; switch (SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, nullptr, &dir_path_ptr)) { case S_OK: @@ -1928,7 +1935,7 @@ Error os_file_mtime(OsFile file, OsTimeStamp *mtime) { FILETIME last_write_time; if (!GetFileTime(file, nullptr, nullptr, &last_write_time)) return ErrorUnexpected; - mtime->sec = last_write_time.dwLowDateTime | (last_write_time.dwHighDateTime << 32); + mtime->sec = (((ULONGLONG) last_write_time.dwHighDateTime) << 32) + last_write_time.dwLowDateTime; mtime->nsec = 0; return ErrorNone; #elif defined(ZIG_OS_LINUX) @@ -2011,7 +2018,8 @@ Error os_file_overwrite(OsFile file, Buf *contents) { return ErrorFileSystem; if (!SetEndOfFile(file)) return ErrorFileSystem; - if (!WriteFile(file, buf_ptr(contents), buf_len(contents), nullptr, nullptr)) + DWORD bytes_written; + if (!WriteFile(file, buf_ptr(contents), buf_len(contents), &bytes_written, nullptr)) return ErrorFileSystem; return ErrorNone; #else diff --git a/src/os.hpp b/src/os.hpp index 1054bf24a..30083971e 100644 --- a/src/os.hpp +++ b/src/os.hpp @@ -114,7 +114,7 @@ int os_copy_file(Buf *src_path, Buf *dest_path); Error ATTRIBUTE_MUST_USE os_fetch_file(FILE *file, Buf *out_contents, bool skip_shebang); Error ATTRIBUTE_MUST_USE os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang); -int os_get_cwd(Buf *out_cwd); +Error ATTRIBUTE_MUST_USE os_get_cwd(Buf *out_cwd); bool os_stderr_tty(void); void os_stderr_set_color(TermColor color); diff --git a/src/windows_com.hpp b/src/windows_com.hpp index 4c807218c..f9833e091 100644 --- a/src/windows_com.hpp +++ b/src/windows_com.hpp @@ -28,6 +28,9 @@ #include #include +// Standard headers +#include + // COM support header files #include diff --git a/std/os/windows/advapi32.zig b/std/os/windows/advapi32.zig index d0a3ec41e..65122545d 100644 --- a/std/os/windows/advapi32.zig +++ b/std/os/windows/advapi32.zig @@ -11,18 +11,6 @@ pub const HKEY__ = extern struct { }; pub const LSTATUS = LONG; -pub extern "advapi32" stdcallcc fn CryptAcquireContextA( - phProv: *HCRYPTPROV, - pszContainer: ?LPCSTR, - pszProvider: ?LPCSTR, - dwProvType: DWORD, - dwFlags: DWORD, -) BOOL; - -pub extern "advapi32" stdcallcc fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) BOOL; - -pub extern "advapi32" stdcallcc fn CryptGenRandom(hProv: HCRYPTPROV, dwLen: DWORD, pbBuffer: [*]BYTE) BOOL; - pub extern "advapi32" stdcallcc fn RegOpenKeyExW( hKey: HKEY, lpSubKey: LPCWSTR, diff --git a/std/special/build_file_template.zig b/std/special/build_file_template.zig deleted file mode 100644 index 11e964769..000000000 --- a/std/special/build_file_template.zig +++ /dev/null @@ -1,10 +0,0 @@ -const Builder = @import("std").build.Builder; - -pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); - const exe = b.addExecutable("YOUR_NAME_HERE", "src/main.zig"); - exe.setBuildMode(mode); - - b.default_step.dependOn(&exe.step); - b.installArtifact(exe); -} diff --git a/std/special/init-exe/build.zig b/std/special/init-exe/build.zig new file mode 100644 index 000000000..21a260056 --- /dev/null +++ b/std/special/init-exe/build.zig @@ -0,0 +1,15 @@ +const Builder = @import("std").build.Builder; + +pub fn build(b: *Builder) void { + const mode = b.standardReleaseOptions(); + const exe = b.addExecutable("$", "src/main.zig"); + exe.setBuildMode(mode); + + const run_step = b.step("run", "Run the app"); + const run_cmd = b.addCommand(".", b.env_map, [][]const u8{exe.getOutputPath()}); + run_step.dependOn(&run_cmd.step); + run_cmd.step.dependOn(&exe.step); + + b.default_step.dependOn(&exe.step); + b.installArtifact(exe); +} diff --git a/std/special/init-exe/src/main.zig b/std/special/init-exe/src/main.zig new file mode 100644 index 000000000..71034d1bf --- /dev/null +++ b/std/special/init-exe/src/main.zig @@ -0,0 +1,5 @@ +const std = @import("std"); + +pub fn main() error!void { + std.debug.warn("All your base are belong to us.\n"); +} diff --git a/std/special/init-lib/build.zig b/std/special/init-lib/build.zig new file mode 100644 index 000000000..9557ccf10 --- /dev/null +++ b/std/special/init-lib/build.zig @@ -0,0 +1,16 @@ +const Builder = @import("std").build.Builder; + +pub fn build(b: *Builder) void { + const mode = b.standardReleaseOptions(); + const lib = b.addStaticLibrary("$", "src/main.zig"); + lib.setBuildMode(mode); + + var main_tests = b.addTest("src/main.zig"); + main_tests.setBuildMode(mode); + + const test_step = b.step("test", "Run library tests"); + test_step.dependOn(&main_tests.step); + + b.default_step.dependOn(&lib.step); + b.installArtifact(lib); +} diff --git a/std/special/init-lib/src/main.zig b/std/special/init-lib/src/main.zig new file mode 100644 index 000000000..27fdeb203 --- /dev/null +++ b/std/special/init-lib/src/main.zig @@ -0,0 +1,10 @@ +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; + +export fn add(a: i32, b: i32) i32 { + return a + b; +} + +test "basic add functionality" { + assertOrPanic(add(3, 7) == 10); +} diff --git a/test/behavior.zig b/test/behavior.zig index 3223131d0..b91d41c74 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -71,4 +71,5 @@ comptime { _ = @import("cases/void.zig"); _ = @import("cases/while.zig"); _ = @import("cases/widening.zig"); + _ = @import("cases/bit_shifting.zig"); } diff --git a/test/cases/align.zig b/test/cases/align.zig index e052c3c3a..838935f53 100644 --- a/test/cases/align.zig +++ b/test/cases/align.zig @@ -219,3 +219,12 @@ test "alignment of structs" { b: *i32, }) == @alignOf(usize)); } + +test "alignment of extern() void" { + var runtime_nothing = nothing; + const casted1 = @ptrCast(*const u8, runtime_nothing); + const casted2 = @ptrCast(extern fn () void, casted1); + casted2(); +} + +extern fn nothing() void {} diff --git a/test/cases/bit_shifting.zig b/test/cases/bit_shifting.zig new file mode 100644 index 000000000..325e765bb --- /dev/null +++ b/test/cases/bit_shifting.zig @@ -0,0 +1,88 @@ +const std = @import("std"); +const assert = std.debug.assert; + +fn ShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime V: type) type { + assert(Key == @IntType(false, Key.bit_count)); + assert(Key.bit_count >= mask_bit_count); + const ShardKey = @IntType(false, mask_bit_count); + const shift_amount = Key.bit_count - ShardKey.bit_count; + return struct { + const Self = @This(); + shards: [1 << ShardKey.bit_count]?*Node, + + pub fn create() Self { + return Self{ .shards = []?*Node{null} ** (1 << ShardKey.bit_count) }; + } + + fn getShardKey(key: Key) ShardKey { + // https://github.com/ziglang/zig/issues/1544 + // this special case is needed because you can't u32 >> 32. + if (ShardKey == u0) return 0; + + // this can be u1 >> u0 + const shard_key = key >> shift_amount; + + // TODO: https://github.com/ziglang/zig/issues/1544 + // This cast could be implicit if we teach the compiler that + // u32 >> 30 -> u2 + return @intCast(ShardKey, shard_key); + } + + pub fn put(self: *Self, node: *Node) void { + const shard_key = Self.getShardKey(node.key); + node.next = self.shards[shard_key]; + self.shards[shard_key] = node; + } + + pub fn get(self: *Self, key: Key) ?*Node { + const shard_key = Self.getShardKey(key); + var maybe_node = self.shards[shard_key]; + while (maybe_node) |node| : (maybe_node = node.next) { + if (node.key == key) return node; + } + return null; + } + + pub const Node = struct { + key: Key, + value: V, + next: ?*Node, + + pub fn init(self: *Node, key: Key, value: V) void { + self.key = key; + self.value = value; + self.next = null; + } + }; + }; +} + +test "sharded table" { + // realistic 16-way sharding + testShardedTable(u32, 4, 8); + + testShardedTable(u5, 0, 32); // ShardKey == u0 + testShardedTable(u5, 2, 32); + testShardedTable(u5, 5, 32); + + testShardedTable(u1, 0, 2); + testShardedTable(u1, 1, 2); // this does u1 >> u0 + + testShardedTable(u0, 0, 1); +} +fn testShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime node_count: comptime_int) void { + const Table = ShardedTable(Key, mask_bit_count, void); + + var table = Table.create(); + var node_buffer: [node_count]Table.Node = undefined; + for (node_buffer) |*node, i| { + const key = @intCast(Key, i); + assert(table.get(key) == null); + node.init(key, {}); + table.put(node); + } + + for (node_buffer) |*node, i| { + assert(table.get(@intCast(Key, i)) == node); + } +} diff --git a/test/cases/bitcast.zig b/test/cases/bitcast.zig index 878140954..0857f88e5 100644 --- a/test/cases/bitcast.zig +++ b/test/cases/bitcast.zig @@ -16,3 +16,20 @@ fn conv(x: i32) u32 { fn conv2(x: u32) i32 { return @bitCast(i32, x); } + +test "@bitCast extern enum to its integer type" { + const SOCK = extern enum { + A, + B, + + fn testBitCastExternEnum() void { + var SOCK_DGRAM = @This().B; + var sock_dgram = @bitCast(c_int, SOCK_DGRAM); + assert(sock_dgram == 1); + } + }; + + SOCK.testBitCastExternEnum(); + comptime SOCK.testBitCastExternEnum(); +} + diff --git a/test/cases/eval.zig b/test/cases/eval.zig index 7e9c9a739..acb3da72c 100644 --- a/test/cases/eval.zig +++ b/test/cases/eval.zig @@ -682,3 +682,31 @@ test "refer to the type of a generic function" { } fn doNothingWithType(comptime T: type) void {} + +test "zero extend from u0 to u1" { + var zero_u0: u0 = 0; + var zero_u1: u1 = zero_u0; + assert(zero_u1 == 0); +} + +test "bit shift a u1" { + var x: u1 = 1; + var y = x << 0; + assert(y == 1); +} + +test "@intCast to a u0" { + var x: u8 = 0; + var y: u0 = @intCast(u0, x); + assert(y == 0); +} + +test "@bytesToslice on a packed struct" { + const F = packed struct { + a: u8, + }; + + var b = [1]u8{9}; + var f = @bytesToSlice(F, b); + assert(f[0].a == 9); +} diff --git a/test/cases/fn.zig b/test/cases/fn.zig index a862f85b0..8908bd785 100644 --- a/test/cases/fn.zig +++ b/test/cases/fn.zig @@ -191,3 +191,17 @@ test "return inner function which references comptime variable of outer function var func = outer(10); assert(func(3) == 7); } + +test "extern struct with stdcallcc fn pointer" { + const S = extern struct { + ptr: stdcallcc fn () i32, + + stdcallcc fn foo() i32 { + return 1234; + } + }; + + var s: S = undefined; + s.ptr = S.foo; + assert(s.ptr() == 1234); +} diff --git a/test/cases/struct.zig b/test/cases/struct.zig index 163c69e67..4ca013544 100644 --- a/test/cases/struct.zig +++ b/test/cases/struct.zig @@ -437,3 +437,19 @@ test "call method with mutable reference to struct with no fields" { assert(S.do(&s)); assert(s.do()); } + +test "implicit cast packed struct field to const ptr" { + const LevelUpMove = packed struct { + move_id: u9, + level: u7, + + fn toInt(value: *const u7) u7 { + return value.*; + } + }; + + var lup: LevelUpMove = undefined; + lup.level = 12; + const res = LevelUpMove.toInt(lup.level); + assert(res == 12); +} diff --git a/test/cli.zig b/test/cli.zig new file mode 100644 index 000000000..f65dabc9f --- /dev/null +++ b/test/cli.zig @@ -0,0 +1,92 @@ +const std = @import("std"); +const os = std.os; +const assertOrPanic = std.debug.assertOrPanic; + +var a: *std.mem.Allocator = undefined; + +pub fn main() !void { + var direct_allocator = std.heap.DirectAllocator.init(); + defer direct_allocator.deinit(); + + var arena = std.heap.ArenaAllocator.init(&direct_allocator.allocator); + defer arena.deinit(); + + var arg_it = os.args(); + + // skip my own exe name + _ = arg_it.skip(); + + a = &arena.allocator; + + const zig_exe_rel = try (arg_it.next(a) orelse { + std.debug.warn("Expected first argument to be path to zig compiler\n"); + return error.InvalidArgs; + }); + const cache_root = try (arg_it.next(a) orelse { + std.debug.warn("Expected second argument to be cache root directory path\n"); + return error.InvalidArgs; + }); + const zig_exe = try os.path.resolve(a, zig_exe_rel); + + try testZigInitLib(zig_exe, cache_root); + try testZigInitExe(zig_exe, cache_root); +} + +fn unwrapArg(arg: UnwrapArgError![]u8) UnwrapArgError![]u8 { + return arg catch |err| { + warn("Unable to parse command line: {}\n", err); + return err; + }; +} + +fn printCmd(cwd: []const u8, argv: []const []const u8) void { + std.debug.warn("cd {} && ", cwd); + for (argv) |arg| { + std.debug.warn("{} ", arg); + } + std.debug.warn("\n"); +} + +fn exec(cwd: []const u8, argv: []const []const u8) !os.ChildProcess.ExecResult { + const max_output_size = 100 * 1024; + const result = os.ChildProcess.exec(a, argv, cwd, null, max_output_size) catch |err| { + std.debug.warn("The following command failed:\n"); + printCmd(cwd, argv); + return err; + }; + switch (result.term) { + os.ChildProcess.Term.Exited => |code| { + if (code != 0) { + std.debug.warn("The following command exited with error code {}:\n", code); + printCmd(cwd, argv); + std.debug.warn("stderr:\n{}\n", result.stderr); + return error.CommandFailed; + } + }, + else => { + std.debug.warn("The following command terminated unexpectedly:\n"); + printCmd(cwd, argv); + std.debug.warn("stderr:\n{}\n", result.stderr); + return error.CommandFailed; + }, + } + return result; +} + +fn testZigInitLib(zig_exe: []const u8, cache_root: []const u8) !void { + const dir_path = try os.path.join(a, cache_root, "clitest"); + try os.deleteTree(a, dir_path); + try os.makeDir(dir_path); + _ = try exec(dir_path, [][]const u8{ zig_exe, "init-lib" }); + const test_result = try exec(dir_path, [][]const u8{ zig_exe, "build", "test" }); + assertOrPanic(std.mem.endsWith(u8, test_result.stderr, "All tests passed.\n")); +} + +fn testZigInitExe(zig_exe: []const u8, cache_root: []const u8) !void { + const dir_path = try os.path.join(a, cache_root, "clitest"); + try os.deleteTree(a, dir_path); + try os.makeDir(dir_path); + _ = try exec(dir_path, [][]const u8{ zig_exe, "init-exe" }); + const run_result = try exec(dir_path, [][]const u8{ zig_exe, "build", "run" }); + assertOrPanic(std.mem.eql(u8, run_result.stderr, "All your base are belong to us.\n")); +} diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 40afc6df2..a1dd33fb4 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,29 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "@ptrCast a 0 bit type to a non- 0 bit type", + \\export fn entry() bool { + \\ var x: u0 = 0; + \\ const p = @ptrCast(?*u0, &x); + \\ return p == null; + \\} + , + ".tmp_source.zig:3:15: error: '*u0' and '?*u0' do not have the same in-memory representation", + ".tmp_source.zig:3:31: note: '*u0' has no in-memory bits", + ".tmp_source.zig:3:24: note: '?*u0' has in-memory bits", + ); + + cases.add( + "comparing a non-optional pointer against null", + \\export fn entry() void { + \\ var x: i32 = 1; + \\ _ = &x == null; + \\} + , + ".tmp_source.zig:3:12: error: comparison against null can only be done with optionals", + ); + cases.add( "non error sets used in merge error sets operator", \\export fn foo() void { diff --git a/test/runtime_safety.zig b/test/runtime_safety.zig index 3d58dfe74..ece6c2283 100644 --- a/test/runtime_safety.zig +++ b/test/runtime_safety.zig @@ -249,6 +249,19 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { \\} ); + cases.addRuntimeSafety("value does not fit in shortening cast - u0", + \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { + \\ @import("std").os.exit(126); + \\} + \\pub fn main() !void { + \\ const x = shorten_cast(1); + \\ if (x == 0) return error.Whatever; + \\} + \\fn shorten_cast(x: u8) u0 { + \\ return @intCast(u0, x); + \\} + ); + cases.addRuntimeSafety("signed integer not fitting in cast to unsigned integer", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); diff --git a/test/tests.zig b/test/tests.zig index a0e179207..88908e877 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -103,6 +103,21 @@ pub fn addBuildExampleTests(b: *build.Builder, test_filter: ?[]const u8, modes: return cases.step; } +pub fn addCliTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { + const step = b.step("test-cli", "Test the command line interface"); + + const exe = b.addExecutable("test-cli", "test/cli.zig"); + const run_cmd = b.addCommand(null, b.env_map, [][]const u8{ + b.pathFromRoot(exe.getOutputPath()), + os.path.realAlloc(b.allocator, b.zig_exe) catch unreachable, + b.pathFromRoot(b.cache_root), + }); + run_cmd.step.dependOn(&exe.step); + + step.dependOn(&run_cmd.step); + return step; +} + pub fn addAssembleAndLinkTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { const cases = b.allocator.create(CompareOutputContext{ .b = b,