diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f871ce7e6..ecfc80fdc8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -204,6 +204,7 @@ install(TARGETS zig DESTINATION bin) install(FILES ${C_HEADERS} DESTINATION ${C_HEADERS_DEST}) +install(FILES "${CMAKE_SOURCE_DIR}/std/build.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/c/darwin.zig" DESTINATION "${ZIG_STD_DEST}/c") install(FILES "${CMAKE_SOURCE_DIR}/std/c/index.zig" DESTINATION "${ZIG_STD_DEST}/c") install(FILES "${CMAKE_SOURCE_DIR}/std/c/linux.zig" DESTINATION "${ZIG_STD_DEST}/c") @@ -234,6 +235,7 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/rand.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/rand_test.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/sort.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/special/bootstrap.zig" DESTINATION "${ZIG_STD_DEST}/special") +install(FILES "${CMAKE_SOURCE_DIR}/std/special/build_runner.zig" DESTINATION "${ZIG_STD_DEST}/special") install(FILES "${CMAKE_SOURCE_DIR}/std/special/builtin.zig" DESTINATION "${ZIG_STD_DEST}/special") install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt.zig" DESTINATION "${ZIG_STD_DEST}/special") install(FILES "${CMAKE_SOURCE_DIR}/std/special/test_runner.zig" DESTINATION "${ZIG_STD_DEST}/special") diff --git a/README.md b/README.md index 594abcaa5e..68f9e62627 100644 --- a/README.md +++ b/README.md @@ -82,13 +82,12 @@ the Zig compiler itself: * gcc >= 5.0.0 or clang >= 3.6.0 * cmake >= 2.8.5 -#### Runtime Dependencies +#### Library Dependencies These libraries must be installed on your system, with the development files available. The Zig compiler dynamically links against them. - * LLVM == 4.x - * libclang == 4.x + * LLVM, Clang, and LLD libraries == 4.x ### Debug / Development Build diff --git a/doc/langref.md b/doc/langref.md index 7b6ba4b294..529191bf26 100644 --- a/doc/langref.md +++ b/doc/langref.md @@ -633,3 +633,10 @@ Invokes the panic handler function. By default the panic handler function calls the public `panic` function exposed in the root source file, or if there is not one specified, invokes the one provided in `std/special/panic.zig`. + +### @bitcast(comptime DestType: type, value: var) -> DestType + +Transmutes memory from one type to another without changing any bits. +The source and destination types must have the same size. This function +can be used to, for example, reinterpret a pointer, or convert a `f32` to a +`u32`. diff --git a/src/all_types.hpp b/src/all_types.hpp index 07c409c0f0..347654351c 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1196,6 +1196,7 @@ enum BuiltinFnId { BuiltinFnIdSetGlobalSection, BuiltinFnIdSetGlobalLinkage, BuiltinFnIdPanic, + BuiltinFnIdBitCast, }; struct BuiltinFnEntry { @@ -1719,7 +1720,7 @@ enum IrInstructionId { IrInstructionIdFnProto, IrInstructionIdTestComptime, IrInstructionIdInitEnum, - IrInstructionIdPointerReinterpret, + IrInstructionIdBitCast, IrInstructionIdWidenOrShorten, IrInstructionIdIntToPtr, IrInstructionIdPtrToInt, @@ -2369,10 +2370,11 @@ struct IrInstructionInitEnum { LLVMValueRef tmp_ptr; }; -struct IrInstructionPointerReinterpret { +struct IrInstructionBitCast { IrInstruction base; - IrInstruction *ptr; + IrInstruction *dest_type; + IrInstruction *target; }; struct IrInstructionWidenOrShorten { diff --git a/src/analyze.cpp b/src/analyze.cpp index fc7915da5a..6a669cf425 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -3355,7 +3355,6 @@ bool type_has_bits(TypeTableEntry *type_entry) { bool type_requires_comptime(TypeTableEntry *type_entry) { switch (get_underlying_type(type_entry)->id) { case TypeTableEntryIdInvalid: - case TypeTableEntryIdUnreachable: case TypeTableEntryIdVar: case TypeTableEntryIdTypeDecl: zig_unreachable(); @@ -3383,6 +3382,7 @@ bool type_requires_comptime(TypeTableEntry *type_entry) { case TypeTableEntryIdPointer: case TypeTableEntryIdEnumTag: case TypeTableEntryIdVoid: + case TypeTableEntryIdUnreachable: return false; } zig_unreachable(); diff --git a/src/codegen.cpp b/src/codegen.cpp index d7e4dc17ec..25290bc279 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -47,7 +47,7 @@ static void init_darwin_native(CodeGen *g) { } } -static PackageTableEntry *new_package(const char *root_src_dir, const char *root_src_path) { +PackageTableEntry *new_package(const char *root_src_dir, const char *root_src_path) { PackageTableEntry *entry = allocate(1); entry->package_table.init(4); buf_init_from_str(&entry->root_src_dir, root_src_dir); @@ -1345,12 +1345,12 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, zig_unreachable(); } -static LLVMValueRef ir_render_pointer_reinterpret(CodeGen *g, IrExecutable *executable, - IrInstructionPointerReinterpret *instruction) +static LLVMValueRef ir_render_bitcast(CodeGen *g, IrExecutable *executable, + IrInstructionBitCast *instruction) { TypeTableEntry *wanted_type = instruction->base.value.type; - LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); - return LLVMBuildBitCast(g->builder, ptr, wanted_type->type_ref, ""); + LLVMValueRef target = ir_llvm_value(g, instruction->target); + return LLVMBuildBitCast(g->builder, target, wanted_type->type_ref, ""); } static LLVMValueRef ir_render_widen_or_shorten(CodeGen *g, IrExecutable *executable, @@ -2776,8 +2776,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction); case IrInstructionIdStructInit: return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction); - case IrInstructionIdPointerReinterpret: - return ir_render_pointer_reinterpret(g, executable, (IrInstructionPointerReinterpret *)instruction); + case IrInstructionIdBitCast: + return ir_render_bitcast(g, executable, (IrInstructionBitCast *)instruction); case IrInstructionIdWidenOrShorten: return ir_render_widen_or_shorten(g, executable, (IrInstructionWidenOrShorten *)instruction); case IrInstructionIdPtrToInt: @@ -3638,8 +3638,14 @@ static void do_code_gen(CodeGen *g) { } else { assert(var->gen_arg_index != SIZE_MAX); TypeTableEntry *gen_type; + FnGenParamInfo *gen_info = &fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index]; + if (handle_is_ptr(var->value->type)) { - gen_type = fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index].type; + if (gen_info->is_byval) { + gen_type = var->value->type; + } else { + gen_type = gen_info->type; + } var->value_ref = LLVMGetParam(fn, var->gen_arg_index); } else { gen_type = var->value->type; @@ -4254,6 +4260,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdSetGlobalSection, "setGlobalSection", 2); create_builtin_fn(g, BuiltinFnIdSetGlobalLinkage, "setGlobalLinkage", 2); create_builtin_fn(g, BuiltinFnIdPanic, "panic", 1); + create_builtin_fn(g, BuiltinFnIdBitCast, "bitcast", 2); } static void add_compile_var(CodeGen *g, const char *name, ConstExprValue *value) { diff --git a/src/codegen.hpp b/src/codegen.hpp index 5b39e3d36c..6b493e4464 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -45,6 +45,7 @@ void codegen_set_mios_version_min(CodeGen *g, Buf *mios_version_min); void codegen_set_linker_script(CodeGen *g, const char *linker_script); void codegen_set_omit_zigrt(CodeGen *g, bool omit_zigrt); +PackageTableEntry *new_package(const char *root_src_dir, const char *root_src_path); void codegen_add_root_code(CodeGen *g, Buf *source_dir, Buf *source_basename, Buf *source_code); void codegen_parseh(CodeGen *g, Buf *src_dirname, Buf *src_basename, Buf *source_code); diff --git a/src/ir.cpp b/src/ir.cpp index 9e1ef9339e..0a0756f27a 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -480,8 +480,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionInitEnum *) { return IrInstructionIdInitEnum; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionPointerReinterpret *) { - return IrInstructionIdPointerReinterpret; +static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCast *) { + return IrInstructionIdBitCast; } static constexpr IrInstructionId ir_instruction_id(IrInstructionWidenOrShorten *) { @@ -1940,14 +1940,16 @@ static IrInstruction *ir_build_init_enum_from(IrBuilder *irb, IrInstruction *old return new_instruction; } -static IrInstruction *ir_build_pointer_reinterpret(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *ptr) +static IrInstruction *ir_build_bit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *dest_type, IrInstruction *target) { - IrInstructionPointerReinterpret *instruction = ir_build_instruction( + IrInstructionBitCast *instruction = ir_build_instruction( irb, scope, source_node); - instruction->ptr = ptr; + instruction->dest_type = dest_type; + instruction->target = target; - ir_ref_instruction(ptr, irb->current_basic_block); + if (dest_type) ir_ref_instruction(dest_type, irb->current_basic_block); + ir_ref_instruction(target, irb->current_basic_block); return &instruction->base; } @@ -2664,11 +2666,12 @@ static IrInstruction *ir_instruction_initenum_get_dep(IrInstructionInitEnum *ins } } -static IrInstruction *ir_instruction_pointerreinterpret_get_dep(IrInstructionPointerReinterpret *instruction, +static IrInstruction *ir_instruction_bitcast_get_dep(IrInstructionBitCast *instruction, size_t index) { switch (index) { - case 0: return instruction->ptr; + case 0: return instruction->dest_type; + case 1: return instruction->target; default: return nullptr; } } @@ -2925,8 +2928,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t return ir_instruction_testcomptime_get_dep((IrInstructionTestComptime *) instruction, index); case IrInstructionIdInitEnum: return ir_instruction_initenum_get_dep((IrInstructionInitEnum *) instruction, index); - case IrInstructionIdPointerReinterpret: - return ir_instruction_pointerreinterpret_get_dep((IrInstructionPointerReinterpret *) instruction, index); + case IrInstructionIdBitCast: + return ir_instruction_bitcast_get_dep((IrInstructionBitCast *) instruction, index); case IrInstructionIdWidenOrShorten: return ir_instruction_widenorshorten_get_dep((IrInstructionWidenOrShorten *) instruction, index); case IrInstructionIdIntToPtr: @@ -4197,6 +4200,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return ir_build_panic(irb, scope, node, arg0_value); } + case BuiltinFnIdBitCast: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_instruction) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_instruction) + return arg1_value; + + return ir_build_bit_cast(irb, scope, node, arg0_value, arg1_value); + } } zig_unreachable(); } @@ -6364,34 +6381,6 @@ static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *sourc return result; } -static IrInstruction *ir_analyze_pointer_reinterpret(IrAnalyze *ira, IrInstruction *source_instr, - IrInstruction *ptr, TypeTableEntry *wanted_type) -{ - if (ptr->value.type->id != TypeTableEntryIdPointer && - ptr->value.type->id != TypeTableEntryIdMaybe) - { - ir_add_error(ira, ptr, buf_sprintf("expected pointer, found '%s'", buf_ptr(&ptr->value.type->name))); - return ira->codegen->invalid_instruction; - } - - if (instr_is_comptime(ptr)) { - ConstExprValue *val = ir_resolve_const(ira, ptr, UndefOk); - if (!val) - return ira->codegen->invalid_instruction; - - IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, - source_instr->scope, source_instr->source_node); - const_instruction->base.value = *val; - const_instruction->base.value.type = wanted_type; - return &const_instruction->base; - } - - IrInstruction *result = ir_build_pointer_reinterpret(&ira->new_irb, source_instr->scope, - source_instr->source_node, ptr); - result->value.type = wanted_type; - return result; -} - static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) { @@ -6829,24 +6818,6 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } } - // explicit cast from pointer to another pointer - if ((actual_type->id == TypeTableEntryIdPointer || actual_type->id == TypeTableEntryIdFn) && - (wanted_type->id == TypeTableEntryIdPointer || wanted_type->id == TypeTableEntryIdFn)) - { - return ir_analyze_pointer_reinterpret(ira, source_instr, value, wanted_type); - } - - // explicit cast from maybe pointer to another maybe pointer - if (actual_type->id == TypeTableEntryIdMaybe && - (actual_type->data.maybe.child_type->id == TypeTableEntryIdPointer || - actual_type->data.maybe.child_type->id == TypeTableEntryIdFn) && - wanted_type->id == TypeTableEntryIdMaybe && - (wanted_type->data.maybe.child_type->id == TypeTableEntryIdPointer || - wanted_type->data.maybe.child_type->id == TypeTableEntryIdFn)) - { - return ir_analyze_pointer_reinterpret(ira, source_instr, value, wanted_type); - } - // explicit cast from child type of maybe type to maybe type if (wanted_type->id == TypeTableEntryIdMaybe) { if (types_match_const_cast_only(wanted_type->data.maybe.child_type, actual_type)) { @@ -8986,6 +8957,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc ConstExprValue *array_ptr_val; if (array_ptr->value.special != ConstValSpecialRuntime && + array_ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar && (array_ptr_val = const_ptr_pointee(&array_ptr->value)) && array_ptr_val->special != ConstValSpecialRuntime && (array_type->id != TypeTableEntryIdPointer || @@ -12210,6 +12182,50 @@ static TypeTableEntry *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstructio return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable); } +static TypeTableEntry *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstructionBitCast *instruction) { + IrInstruction *dest_type_value = instruction->dest_type->other; + TypeTableEntry *dest_type = ir_resolve_type(ira, dest_type_value); + if (type_is_invalid(dest_type)) + return ira->codegen->builtin_types.entry_invalid; + + IrInstruction *target = instruction->target->other; + TypeTableEntry *src_type = target->value.type; + if (type_is_invalid(src_type)) + return ira->codegen->builtin_types.entry_invalid; + + ensure_complete_type(ira->codegen, dest_type); + ensure_complete_type(ira->codegen, src_type); + + uint64_t dest_size_bytes = type_size(ira->codegen, dest_type); + uint64_t src_size_bytes = type_size(ira->codegen, src_type); + if (dest_size_bytes != src_size_bytes) { + ir_add_error(ira, &instruction->base, + buf_sprintf("destination type '%s' has size %" PRIu64 " but source type '%s' has size %" PRIu64, + buf_ptr(&dest_type->name), dest_size_bytes, + buf_ptr(&src_type->name), src_size_bytes)); + return ira->codegen->builtin_types.entry_invalid; + } + + if (instr_is_comptime(target) && src_type->id == dest_type->id && + (src_type->id == TypeTableEntryIdPointer || src_type->id == TypeTableEntryIdMaybe)) + { + ConstExprValue *val = ir_resolve_const(ira, target, UndefOk); + if (!val) + return ira->codegen->builtin_types.entry_invalid; + + ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); + *out_val = *val; + out_val->type = dest_type; + return dest_type; + } + + IrInstruction *result = ir_build_bit_cast(&ira->new_irb, instruction->base.scope, + instruction->base.source_node, nullptr, target); + ir_link_new_instruction(result, &instruction->base); + result->value.type = dest_type; + return dest_type; +} + static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira, IrInstructionDeclRef *instruction) { @@ -12283,7 +12299,6 @@ static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira, static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { switch (instruction->id) { case IrInstructionIdInvalid: - case IrInstructionIdPointerReinterpret: case IrInstructionIdWidenOrShorten: case IrInstructionIdIntToPtr: case IrInstructionIdPtrToInt: @@ -12449,6 +12464,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_decl_ref(ira, (IrInstructionDeclRef *)instruction); case IrInstructionIdPanic: return ir_analyze_instruction_panic(ira, (IrInstructionPanic *)instruction); + case IrInstructionIdBitCast: + return ir_analyze_instruction_bit_cast(ira, (IrInstructionBitCast *)instruction); case IrInstructionIdMaybeWrap: case IrInstructionIdErrWrapCode: case IrInstructionIdErrWrapPayload: @@ -12620,7 +12637,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdFnProto: case IrInstructionIdTestComptime: case IrInstructionIdInitEnum: - case IrInstructionIdPointerReinterpret: + case IrInstructionIdBitCast: case IrInstructionIdWidenOrShorten: case IrInstructionIdPtrToInt: case IrInstructionIdIntToPtr: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 376de228d2..9446be43bd 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -765,9 +765,9 @@ static void ir_print_init_enum(IrPrint *irp, IrInstructionInitEnum *instruction) fprintf(irp->f, "}"); } -static void ir_print_pointer_reinterpret(IrPrint *irp, IrInstructionPointerReinterpret *instruction) { - fprintf(irp->f, "@pointerReinterpret("); - ir_print_other_instruction(irp, instruction->ptr); +static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) { + fprintf(irp->f, "@bitcast("); + ir_print_other_instruction(irp, instruction->target); fprintf(irp->f, ")"); } @@ -1098,8 +1098,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdInitEnum: ir_print_init_enum(irp, (IrInstructionInitEnum *)instruction); break; - case IrInstructionIdPointerReinterpret: - ir_print_pointer_reinterpret(irp, (IrInstructionPointerReinterpret *)instruction); + case IrInstructionIdBitCast: + ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction); break; case IrInstructionIdWidenOrShorten: ir_print_widen_or_shorten(irp, (IrInstructionWidenOrShorten *)instruction); diff --git a/src/main.cpp b/src/main.cpp index 2705dcbf4a..6f712c0f6a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,46 +19,48 @@ static int usage(const char *arg0) { fprintf(stderr, "Usage: %s [command] [options]\n" "Commands:\n" - " build [sources] create executable, object, or library from source\n" - " test [sources] create and run a test build\n" + " build build project from build.zig\n" + " build_exe [source] create executable from source\n" + " build_lib [source] create library from source\n" + " build_obj [source] create object from source\n" " parseh [source] convert a c header file to zig extern declarations\n" - " version print version number and exit\n" " targets list available compilation targets\n" + " test [source] create and run a test build\n" + " version print version number and exit\n" "Options:\n" + " --ar-path [path] set the path to ar\n" + " --color [auto|off|on] enable or disable colored error messages\n" + " --dynamic-linker [path] set the path to ld.so\n" + " --each-lib-rpath add rpath for each used dynamic library\n" + " --ld-path [path] set the path to the linker\n" + " --libc-include-dir [path] directory where libc stdlib.h resides\n" + " --libc-lib-dir [path] directory where libc crt1.o resides\n" + " --libc-static-lib-dir [path] directory where libc crtbegin.o resides\n" + " --library [lib] link against lib\n" + " --library-path [dir] add a directory to the library search path\n" + " --linker-script [path] use a custom linker script\n" + " --name [name] override output name\n" + " --output [file] override destination path\n" " --release build with optimizations on and debug protection off\n" " --static output will be statically linked\n" " --strip exclude debug symbols\n" - " --export [exe|lib|obj] override output type\n" - " --name [name] override output name\n" - " --output [file] override destination path\n" - " --verbose turn on compiler debug output\n" - " --color [auto|off|on] enable or disable colored error messages\n" - " --libc-lib-dir [path] directory where libc crt1.o resides\n" - " --libc-static-lib-dir [path] directory where libc crtbegin.o resides\n" - " --libc-include-dir [path] directory where libc stdlib.h resides\n" - " --zig-std-dir [path] directory where zig standard library resides\n" - " --dynamic-linker [path] set the path to ld.so\n" - " --ld-path [path] set the path to the linker\n" - " --ar-path [path] set the path to ar\n" - " -isystem [dir] add additional search path for other .h files\n" - " -dirafter [dir] same as -isystem but do it last\n" - " --library-path [dir] add a directory to the library search path\n" - " -L[dir] alias for --library-path\n" - " --library [lib] link against lib\n" " --target-arch [name] specify target architecture\n" - " --target-os [name] specify target operating system\n" " --target-environ [name] specify target environment\n" - " -mwindows (windows only) --subsystem windows to the linker\n" - " -mconsole (windows only) --subsystem console to the linker\n" - " -municode (windows only) link with unicode\n" - " -mlinker-version [ver] (darwin only) override linker version\n" - " -rdynamic add all symbols to the dynamic symbol table\n" - " -mmacosx-version-min [ver] (darwin only) set Mac OS X deployment target\n" - " -mios-version-min [ver] (darwin only) set iOS deployment target\n" + " --target-os [name] specify target operating system\n" + " --verbose turn on compiler debug output\n" + " --zig-std-dir [path] directory where zig standard library resides\n" + " -L[dir] alias for --library-path\n" + " -dirafter [dir] same as -isystem but do it last\n" " -framework [name] (darwin only) link against framework\n" - " --linker-script [path] use a custom linker script\n" + " -isystem [dir] add additional search path for other .h files\n" + " -mconsole (windows only) --subsystem console to the linker\n" + " -mios-version-min [ver] (darwin only) set iOS deployment target\n" + " -mlinker-version [ver] (darwin only) override linker version\n" + " -mmacosx-version-min [ver] (darwin only) set Mac OS X deployment target\n" + " -municode (windows only) link with unicode\n" + " -mwindows (windows only) --subsystem windows to the linker\n" + " -rdynamic add all symbols to the dynamic symbol table\n" " -rpath [path] add directory to the runtime library search path\n" - " --each-lib-rpath add rpath for each used dynamic library\n" , arg0); return EXIT_FAILURE; } @@ -144,6 +146,62 @@ int main(int argc, char **argv) { ZigList rpath_list = {0}; bool each_lib_rpath = false; + if (argc >= 2 && strcmp(argv[1], "build") == 0) { + const char *zig_exe_path = arg0; + + init_all_targets(); + + Buf *zig_std_dir = buf_create_from_str(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); + + ZigList args = {0}; + args.append(zig_exe_path); + for (int i = 2; i < argc; i += 1) { + if (strcmp(argv[i], "--verbose") == 0) { + verbose = true; + args.append(argv[i]); + } else { + args.append(argv[i]); + } + } + + + Buf root_source_dir = BUF_INIT; + Buf root_source_code = BUF_INIT; + Buf root_source_name = BUF_INIT; + os_path_split(build_runner_path, &root_source_dir, &root_source_name); + if ((err = os_fetch_file_path(build_runner_path, &root_source_code))) { + fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(build_runner_path), err_str(err)); + return 1; + } + CodeGen *g = codegen_create(&root_source_dir, nullptr); + codegen_set_out_name(g, buf_create_from_str("build")); + codegen_set_out_type(g, OutTypeExe); + codegen_set_verbose(g, verbose); + + PackageTableEntry *build_pkg = new_package(".", "build.zig"); + build_pkg->package_table.put(buf_create_from_str("std"), g->std_package); + g->root_package->package_table.put(buf_create_from_str("@build"), build_pkg); + codegen_add_root_code(g, &root_source_dir, &root_source_name, &root_source_code); + codegen_link(g, "build"); + + Termination term; + os_spawn_process("./build", args, &term); + if (term.how != TerminationIdClean || term.code != 0) { + fprintf(stderr, "\nBuild failed. Use the following command to reproduce the failure:\n"); + fprintf(stderr, "./build"); + for (size_t i = 0; i < args.length; i += 1) { + fprintf(stderr, " \"%s\"", args.at(i)); + } + fprintf(stderr, "\n"); + } + return (term.how == TerminationIdClean) ? term.code : -1; + } + for (int i = 1; i < argc; i += 1) { char *arg = argv[i]; @@ -177,16 +235,6 @@ int main(int argc, char **argv) { return usage(arg0); } else if (strcmp(arg, "--output") == 0) { out_file = argv[i]; - } else if (strcmp(arg, "--export") == 0) { - if (strcmp(argv[i], "exe") == 0) { - out_type = OutTypeExe; - } else if (strcmp(argv[i], "lib") == 0) { - out_type = OutTypeLib; - } else if (strcmp(argv[i], "obj") == 0) { - out_type = OutTypeObj; - } else { - return usage(arg0); - } } else if (strcmp(arg, "--color") == 0) { if (strcmp(argv[i], "auto") == 0) { color = ErrColorAuto; @@ -243,8 +291,15 @@ int main(int argc, char **argv) { } } } else if (cmd == CmdInvalid) { - if (strcmp(arg, "build") == 0) { + if (strcmp(arg, "build_exe") == 0) { cmd = CmdBuild; + out_type = OutTypeExe; + } else if (strcmp(arg, "build_obj") == 0) { + cmd = CmdBuild; + out_type = OutTypeObj; + } else if (strcmp(arg, "build_lib") == 0) { + cmd = CmdBuild; + out_type = OutTypeLib; } else if (strcmp(arg, "version") == 0) { cmd = CmdVersion; } else if (strcmp(arg, "parseh") == 0) { @@ -285,15 +340,7 @@ int main(int argc, char **argv) { if (!in_file) return usage(arg0); - if (cmd == CmdBuild && !out_name) { - fprintf(stderr, "--name [name] not provided\n\n"); - return usage(arg0); - } - - if (cmd == CmdBuild && out_type == OutTypeUnknown) { - fprintf(stderr, "--export [exe|lib|obj] not provided\n\n"); - return usage(arg0); - } + assert(cmd != CmdBuild || out_type != OutTypeUnknown); init_all_targets(); @@ -331,6 +378,9 @@ int main(int argc, char **argv) { Buf root_source_dir = BUF_INIT; Buf root_source_code = BUF_INIT; Buf root_source_name = BUF_INIT; + + Buf *buf_out_name = (cmd == CmdTest) ? buf_create_from_str("test") : + (out_name == nullptr) ? nullptr : buf_create_from_str(out_name); if (buf_eql_str(&in_file_buf, "-")) { os_get_cwd(&root_source_dir); if ((err = os_fetch_file(stdin, &root_source_code))) { @@ -338,12 +388,24 @@ int main(int argc, char **argv) { return 1; } buf_init_from_str(&root_source_name, ""); + } else { os_path_split(&in_file_buf, &root_source_dir, &root_source_name); if ((err = os_fetch_file_path(buf_create_from_str(in_file), &root_source_code))) { fprintf(stderr, "unable to open '%s': %s\n", in_file, err_str(err)); return 1; } + + if (cmd == CmdBuild && buf_out_name == nullptr) { + buf_out_name = buf_alloc(); + Buf ext_name = BUF_INIT; + os_path_extname(&root_source_name, buf_out_name, &ext_name); + } + } + + if (cmd == CmdBuild && buf_out_name == nullptr) { + fprintf(stderr, "--name [name] not provided and unable to infer\n\n"); + return usage(arg0); } CodeGen *g = codegen_create(&root_source_dir, target); @@ -361,11 +423,7 @@ int main(int argc, char **argv) { } else if (cmd == CmdTest) { codegen_set_out_type(g, OutTypeExe); } - if (out_name) { - codegen_set_out_name(g, buf_create_from_str(out_name)); - } else if (cmd == CmdTest) { - codegen_set_out_name(g, buf_create_from_str("test")); - } + codegen_set_out_name(g, buf_out_name); if (libc_lib_dir) codegen_set_libc_lib_dir(g, buf_create_from_str(libc_lib_dir)); if (libc_static_lib_dir) diff --git a/src/os.cpp b/src/os.cpp index 391a9df7b4..59561398c7 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -139,6 +139,32 @@ void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename) { if (out_basename) buf_init_from_buf(out_basename, full_path); } +void os_path_extname(Buf *full_path, Buf *out_basename, Buf *out_extname) { + if (buf_len(full_path) == 0) { + buf_init_from_str(out_basename, ""); + buf_init_from_str(out_extname, ""); + return; + } + size_t i = buf_len(full_path) - 1; + while (true) { + if (buf_ptr(full_path)[i] == '.') { + buf_resize(out_basename, 0); + buf_append_mem(out_basename, buf_ptr(full_path), i); + + buf_resize(out_extname, 0); + buf_append_mem(out_extname, buf_ptr(full_path) + i, buf_len(full_path) - i); + return; + } + + if (i == 0) { + buf_init_from_buf(out_basename, full_path); + buf_init_from_str(out_extname, ""); + return; + } + i -= 1; + } +} + void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path) { buf_init_from_buf(out_full_path, dirname); uint8_t c = *(buf_ptr(out_full_path) + buf_len(out_full_path) - 1); diff --git a/src/os.hpp b/src/os.hpp index 1b2649a4ef..c84720fc38 100644 --- a/src/os.hpp +++ b/src/os.hpp @@ -34,6 +34,7 @@ int os_exec_process(const char *exe, ZigList &args, void os_path_dirname(Buf *full_path, Buf *out_dirname); void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename); +void os_path_extname(Buf *full_path, Buf *out_basename, Buf *out_extname); void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path); int os_path_real(Buf *rel_path, Buf *out_abs_path); void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path); diff --git a/std/build.zig b/std/build.zig new file mode 100644 index 0000000000..746800668a --- /dev/null +++ b/std/build.zig @@ -0,0 +1,59 @@ +const io = @import("io.zig"); +const mem = @import("mem.zig"); +const debug = @import("debug.zig"); +const List = @import("list.zig").List; +const Allocator = @import("mem.zig").Allocator; + +error ExtraArg; + +pub const Builder = struct { + zig_exe: []const u8, + allocator: &Allocator, + exe_list: List(&Exe), + + pub fn init(zig_exe: []const u8, allocator: &Allocator) -> Builder { + Builder { + .zig_exe = zig_exe, + .allocator = allocator, + .exe_list = List(&Exe).init(allocator), + } + } + + pub fn addExe(self: &Builder, root_src: []const u8, name: []const u8) -> &Exe { + return self.addExeErr(root_src, name) %% |err| handleErr(err); + } + + pub fn addExeErr(self: &Builder, root_src: []const u8, name: []const u8) -> %&Exe { + const exe = %return self.allocator.create(Exe); + *exe = Exe { + .root_src = root_src, + .name = name, + }; + %return self.exe_list.append(exe); + return exe; + } + + pub fn make(self: &Builder, args: []const []const u8) -> %void { + var verbose = false; + for (args) |arg| { + if (mem.eql(u8, arg, "--verbose")) { + verbose = true; + } else { + %%io.stderr.printf("Unrecognized argument: '{}'\n", arg); + return error.ExtraArg; + } + } + for (self.exe_list.toSlice()) |exe| { + %%io.stderr.printf("TODO: invoke this command:\nzig build_exe {} --name {}\n", exe.root_src, exe.name); + } + } +}; + +const Exe = struct { + root_src: []const u8, + name: []const u8, +}; + +fn handleErr(err: error) -> noreturn { + debug.panic("error: {}\n", @errorName(err)); +} diff --git a/std/debug.zig b/std/debug.zig index 2fff730a93..cc0583dd45 100644 --- a/std/debug.zig +++ b/std/debug.zig @@ -15,7 +15,7 @@ pub fn assert(ok: bool) { var panicking = false; /// This is the default panic implementation. -pub coldcc fn panic(message: []const u8) -> noreturn { +pub coldcc fn panic(comptime format: []const u8, args: ...) -> noreturn { // TODO // if (@atomicRmw(AtomicOp.XChg, &panicking, true, AtomicOrder.SeqCst)) { } if (panicking) { @@ -28,7 +28,7 @@ pub coldcc fn panic(message: []const u8) -> noreturn { panicking = true; } - %%io.stderr.printf("{}\n", message); + %%io.stderr.printf(format, args); %%printStackTrace(); os.abort(); @@ -74,7 +74,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream) -> %void { const name = %return compile_unit.die.getAttrString(st, DW.AT_name); %return out_stream.printf("{} -> {}\n", return_address, name); - maybe_fp = *(&const ?&const u8)(fp); + maybe_fp = *@bitcast(&const ?&const u8, fp); } }, ObjectFormat.coff => { @@ -511,7 +511,6 @@ pub var global_allocator = mem.Allocator { .allocFn = globalAlloc, .reallocFn = globalRealloc, .freeFn = globalFree, - .context = null, }; var some_mem: [100 * 1024]u8 = undefined; diff --git a/std/hash_map.zig b/std/hash_map.zig index d90cbaa7ac..5c2edb33b9 100644 --- a/std/hash_map.zig +++ b/std/hash_map.zig @@ -236,7 +236,7 @@ test "basicHashMapTest" { } fn hash_i32(x: i32) -> u32 { - *(&u32)(&x) + *@bitcast(&u32, &x) } fn eql_i32(a: i32, b: i32) -> bool { a == b diff --git a/std/index.zig b/std/index.zig index 626a3749f7..dce1bdb7a5 100644 --- a/std/index.zig +++ b/std/index.zig @@ -1,3 +1,4 @@ +pub const build = @import("build.zig"); pub const c = @import("c/index.zig"); pub const cstr = @import("cstr.zig"); pub const debug = @import("debug.zig"); diff --git a/std/mem.zig b/std/mem.zig index 3c99029a39..f118a280e1 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -7,12 +7,10 @@ pub const Cmp = math.Cmp; error NoMem; -pub type Context = u8; pub const Allocator = struct { allocFn: fn (self: &Allocator, n: usize) -> %[]u8, reallocFn: fn (self: &Allocator, old_mem: []u8, new_size: usize) -> %[]u8, freeFn: fn (self: &Allocator, mem: []u8), - context: ?&Context, /// Aborts the program if an allocation fails. fn checkedAlloc(self: &Allocator, comptime T: type, n: usize) -> []T { @@ -22,6 +20,14 @@ pub const Allocator = struct { } } + fn create(self: &Allocator, comptime T: type) -> %&T { + &(%return self.alloc(T, 1))[0] + } + + fn destroy(self: &Allocator, ptr: var) { + self.free(ptr[0...1]); + } + fn alloc(self: &Allocator, comptime T: type, n: usize) -> %[]T { const byte_count = %return math.mulOverflow(usize, @sizeOf(T), n); ([]T)(%return self.allocFn(self, byte_count)) @@ -37,6 +43,62 @@ pub const Allocator = struct { } }; +pub const IncrementingAllocator = struct { + allocator: Allocator, + bytes: []u8, + end_index: usize, + + fn init(capacity: usize) -> %IncrementingAllocator { + switch (@compileVar("os")) { + Os.linux, Os.darwin, Os.macosx, Os.ios => { + const p = os.posix; + const addr = p.mmap(null, capacity, p.PROT_READ|p.PROT_WRITE, + p.MAP_PRIVATE|p.MAP_ANONYMOUS|p.MAP_NORESERVE, -1, 0); + if (addr == p.MAP_FAILED) { + return error.NoMem; + } + return IncrementingAllocator { + .allocator = Allocator { + .allocFn = alloc, + .reallocFn = realloc, + .freeFn = free, + }, + .bytes = (&u8)(addr)[0...capacity], + .end_index = 0, + }; + }, + else => @compileError("Unsupported OS"), + } + } + + fn deinit(self: &IncrementingAllocator) { + _ = os.posix.munmap(self.bytes.ptr, self.bytes.len); + } + + fn alloc(allocator: &Allocator, n: usize) -> %[]u8 { + // TODO + //const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator); + const self = @bitcast(&IncrementingAllocator, allocator); + const new_end_index = self.end_index + n; + if (new_end_index > self.bytes.len) { + return error.NoMem; + } + const result = self.bytes[self.end_index...new_end_index]; + self.end_index = new_end_index; + return result; + } + + fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize) -> %[]u8 { + const result = %return alloc(allocator, new_size); + copy(u8, result, old_mem); + return result; + } + + fn free(allocator: &Allocator, bytes: []u8) { + // Do nothing. That's the point of an incrementing allocator. + } +}; + /// Copy all of source into dest at position 0. /// dest.len must be >= source.len. pub fn copy(comptime T: type, dest: []T, source: []const T) { diff --git a/std/os/linux.zig b/std/os/linux.zig index be86136dee..0e616cfc53 100644 --- a/std/os/linux.zig +++ b/std/os/linux.zig @@ -5,16 +5,29 @@ const arch = switch (@compileVar("arch")) { }; const errno = @import("errno.zig"); -pub const MMAP_PROT_NONE = 0; -pub const MMAP_PROT_READ = 1; -pub const MMAP_PROT_WRITE = 2; -pub const MMAP_PROT_EXEC = 4; +pub const PROT_NONE = 0; +pub const PROT_READ = 1; +pub const PROT_WRITE = 2; +pub const PROT_EXEC = 4; +pub const PROT_GROWSDOWN = 0x01000000; +pub const PROT_GROWSUP = 0x02000000; -pub const MMAP_MAP_FILE = 0; -pub const MMAP_MAP_SHARED = 1; -pub const MMAP_MAP_PRIVATE = 2; -pub const MMAP_MAP_FIXED = 16; -pub const MMAP_MAP_ANON = 32; +pub const MAP_FAILED = @maxValue(usize); +pub const MAP_SHARED = 0x01; +pub const MAP_PRIVATE = 0x02; +pub const MAP_TYPE = 0x0f; +pub const MAP_FIXED = 0x10; +pub const MAP_ANONYMOUS = 0x20; +pub const MAP_NORESERVE = 0x4000; +pub const MAP_GROWSDOWN = 0x0100; +pub const MAP_DENYWRITE = 0x0800; +pub const MAP_EXECUTABLE = 0x1000; +pub const MAP_LOCKED = 0x2000; +pub const MAP_POPULATE = 0x8000; +pub const MAP_NONBLOCK = 0x10000; +pub const MAP_STACK = 0x20000; +pub const MAP_HUGETLB = 0x40000; +pub const MAP_FILE = 0; pub const SIGHUP = 1; pub const SIGINT = 2; @@ -226,7 +239,7 @@ pub const AF_MAX = PF_MAX; /// Get the errno from a syscall return value, or 0 for no error. pub fn getErrno(r: usize) -> usize { - const signed_r = *(&isize)(&r); + const signed_r = *@bitcast(&isize, &r); if (signed_r > -4096 and signed_r < 0) usize(-signed_r) else 0 } diff --git a/std/special/build_runner.zig b/std/special/build_runner.zig new file mode 100644 index 0000000000..73a608487a --- /dev/null +++ b/std/special/build_runner.zig @@ -0,0 +1,18 @@ +const root = @import("@build"); +const std = @import("std"); +const io = std.io; +const Builder = std.build.Builder; +const mem = std.mem; + +pub fn main(args: [][]u8) -> %void { + const zig_exe = args[1]; + const leftover_args = args[2...]; + + // TODO use a more general purpose allocator here + var inc_allocator = %%mem.IncrementingAllocator.init(10 * 1024 * 1024); + defer inc_allocator.deinit(); + + var builder = Builder.init(zig_exe, &inc_allocator.allocator); + root.build(&builder); + %return builder.make(leftover_args); +} diff --git a/std/special/compiler_rt.zig b/std/special/compiler_rt.zig index 8f61876305..f5c83becc7 100644 --- a/std/special/compiler_rt.zig +++ b/std/special/compiler_rt.zig @@ -15,7 +15,7 @@ export fn __udivdi3(a: du_int, b: du_int) -> du_int { fn du_int_to_udwords(x: du_int) -> udwords { @setDebugSafety(this, false); - return *(&udwords)(&x); + return *@bitcast(&udwords, &x); } export fn __udivmoddi4(a: du_int, b: du_int, maybe_rem: ?&du_int) -> du_int { @@ -66,7 +66,7 @@ export fn __udivmoddi4(a: du_int, b: du_int, maybe_rem: ?&du_int) -> du_int { if (var rem ?= maybe_rem) { r[high] = n[high] % d[high]; r[low] = 0; - *rem = *(&du_int)(&r[0]); + *rem = *@bitcast(&du_int, &r[0]); } return n[high] / d[high]; } @@ -78,7 +78,7 @@ export fn __udivmoddi4(a: du_int, b: du_int, maybe_rem: ?&du_int) -> du_int { if (var rem ?= maybe_rem) { r[low] = n[low]; r[high] = n[high] & (d[high] - 1); - *rem = *(&du_int)(&r[0]); + *rem = *@bitcast(&du_int, &r[0]); } return n[high] >> @ctz(d[high]); } @@ -89,7 +89,7 @@ export fn __udivmoddi4(a: du_int, b: du_int, maybe_rem: ?&du_int) -> du_int { // 0 <= sr <= n_uword_bits - 2 or sr large if (sr > n_uword_bits - 2) { if (var rem ?= maybe_rem) { - *rem = *(&du_int)(&n[0]); + *rem = *@bitcast(&du_int, &n[0]); } return 0; } @@ -113,12 +113,12 @@ export fn __udivmoddi4(a: du_int, b: du_int, maybe_rem: ?&du_int) -> du_int { *rem = n[low] & (d[low] - 1); } if (d[low] == 1) { - return *(&du_int)(&n[0]); + return *@bitcast(&du_int, &n[0]); } sr = @ctz(d[low]); q[high] = n[high] >> sr; q[low] = (n[high] << (n_uword_bits - sr)) | (n[low] >> sr); - return *(&du_int)(&q[0]); + return *@bitcast(&du_int, &q[0]); } // K X // --- @@ -154,7 +154,7 @@ export fn __udivmoddi4(a: du_int, b: du_int, maybe_rem: ?&du_int) -> du_int { // 0 <= sr <= n_uword_bits - 1 or sr large if (sr > n_uword_bits - 1) { if (var rem ?= maybe_rem) { - *rem = *(&du_int)(&n[0]); + *rem = *@bitcast(&du_int, &n[0]); } return 0; } @@ -191,17 +191,17 @@ export fn __udivmoddi4(a: du_int, b: du_int, maybe_rem: ?&du_int) -> du_int { // r.all -= d.all; // carry = 1; // } - const s: di_int = (di_int)(*(&du_int)(&d[0]) - *(&du_int)(&r[0]) - 1) >> (n_udword_bits - 1); + const s: di_int = (di_int)(*@bitcast(&du_int, &d[0]) - *@bitcast(&du_int, &r[0]) - 1) >> (n_udword_bits - 1); carry = su_int(s & 1); - *(&du_int)(&r[0]) -= *(&du_int)(&d[0]) & u64(s); + *@bitcast(&du_int, &r[0]) -= *@bitcast(&du_int, &d[0]) & u64(s); sr -= 1; } - *(&du_int)(&q[0]) = (*(&du_int)(&q[0]) << 1) | u64(carry); + *@bitcast(&du_int, &q[0]) = (*@bitcast(&du_int, &q[0]) << 1) | u64(carry); if (var rem ?= maybe_rem) { - *rem = *(&du_int)(&r[0]); + *rem = *@bitcast(&du_int, &r[0]); } - return *(&du_int)(&q[0]); + return *@bitcast(&du_int, &q[0]); } export fn __umoddi3(a: du_int, b: du_int) -> du_int { diff --git a/std/special/zigrt.zig b/std/special/zigrt.zig index 148516eb40..6f7911917d 100644 --- a/std/special/zigrt.zig +++ b/std/special/zigrt.zig @@ -1,5 +1,5 @@ // This file contains functions that zig depends on to coordinate between -// multiple .o files. The symbols are defined LinkOnce so that multiple +// multiple .o files. The symbols are defined Weak so that multiple // instances of zig_rt.zig do not conflict with each other. export coldcc fn __zig_panic(message_ptr: &const u8, message_len: usize) -> noreturn { @@ -11,6 +11,6 @@ export coldcc fn __zig_panic(message_ptr: &const u8, message_len: usize) -> nore } else if (@compileVar("os") == Os.freestanding) { while (true) {} } else { - @import("std").debug.panic(message_ptr[0...message_len]); + @import("std").debug.panic("{}\n", message_ptr[0...message_len]); } } diff --git a/test/cases/cast.zig b/test/cases/cast.zig index 928b631339..7f97e6660b 100644 --- a/test/cases/cast.zig +++ b/test/cases/cast.zig @@ -15,7 +15,18 @@ test "numLitIntToPtrCast" { test "pointerReinterpretConstFloatToInt" { const float: f64 = 5.99999999999994648725e-01; const float_ptr = &float; - const int_ptr = (&i32)(float_ptr); + const int_ptr = @bitcast(&i32, float_ptr); const int_val = *int_ptr; assert(int_val == 858993411); } + +test "implicitly cast a pointer to a const pointer of it" { + var x: i32 = 1; + const xp = &x; + funcWithConstPtrPtr(xp); + assert(x == 2); +} + +fn funcWithConstPtrPtr(x: &const &i32) { + **x += 1; +} diff --git a/test/cases/eval.zig b/test/cases/eval.zig index b1d10ca8bf..0d52985329 100644 --- a/test/cases/eval.zig +++ b/test/cases/eval.zig @@ -284,3 +284,18 @@ fn testCompTimeUIntComparisons(x: u32) { @compileError("this condition should be comptime known"); } } + + + +test "const ptr to variable data changes at runtime" { + assert(foo_ref.name[0] == 'a'); + foo_ref.name = "b"; + assert(foo_ref.name[0] == 'b'); +} + +const Foo = struct { + name: []const u8, +}; + +var foo_contents = Foo { .name = "a", }; +const foo_ref = &foo_contents; diff --git a/test/cases/generics.zig b/test/cases/generics.zig index c23b189dc3..68637c614b 100644 --- a/test/cases/generics.zig +++ b/test/cases/generics.zig @@ -121,5 +121,5 @@ test "genericFnWithImplicitCast" { } fn getByte(ptr: ?&const u8) -> u8 {*??ptr} fn getFirstByte(comptime T: type, mem: []const T) -> u8 { - getByte((&const u8)(&mem[0])) + getByte(@bitcast(&const u8, &mem[0])) } diff --git a/test/cases/misc.zig b/test/cases/misc.zig index c26ae8b04a..81b9db3a24 100644 --- a/test/cases/misc.zig +++ b/test/cases/misc.zig @@ -246,15 +246,15 @@ test "typeEquality" { const global_a: i32 = 1234; const global_b: &const i32 = &global_a; -const global_c: &const f32 = (&const f32)(global_b); +const global_c: &const f32 = @bitcast(&const f32, global_b); test "compileTimeGlobalReinterpret" { - const d = (&const i32)(global_c); + const d = @bitcast(&const i32, global_c); assert(*d == 1234); } test "explicitCastMaybePointers" { const a: ?&i32 = undefined; - const b: ?&f32 = (?&f32)(a); + const b: ?&f32 = @bitcast(?&f32, a); } test "genericMallocFree" { @@ -263,7 +263,7 @@ test "genericMallocFree" { } const some_mem : [100]u8 = undefined; fn memAlloc(comptime T: type, n: usize) -> %[]T { - return (&T)(&some_mem[0])[0...n]; + return @bitcast(&T, &some_mem[0])[0...n]; } fn memFree(comptime T: type, memory: []T) { } diff --git a/test/cases/struct.zig b/test/cases/struct.zig index b927c01941..bd69177d4f 100644 --- a/test/cases/struct.zig +++ b/test/cases/struct.zig @@ -41,7 +41,7 @@ const VoidStructFieldsFoo = struct { test "fn" { var foo: StructFoo = undefined; - @memset((&u8)(&foo), 0, @sizeOf(StructFoo)); + @memset(@bitcast(&u8, &foo), 0, @sizeOf(StructFoo)); foo.a += 1; foo.b = foo.a == 1; testFoo(foo); diff --git a/test/run_tests.cpp b/test/run_tests.cpp index 162ba24903..b82431fae1 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -73,10 +73,8 @@ static TestCase *add_simple_case(const char *case_name, const char *source, cons test_case->source_files.at(0).relative_path = tmp_source_path; test_case->source_files.at(0).source_code = source; - test_case->compiler_args.append("build"); + test_case->compiler_args.append("build_exe"); test_case->compiler_args.append(tmp_source_path); - test_case->compiler_args.append("--export"); - test_case->compiler_args.append("exe"); test_case->compiler_args.append("--name"); test_case->compiler_args.append("test"); test_case->compiler_args.append("--output"); @@ -113,15 +111,12 @@ static TestCase *add_compile_fail_case(const char *case_name, const char *source test_case->compile_errors.append(arg); } - test_case->compiler_args.append("build"); + test_case->compiler_args.append("build_obj"); test_case->compiler_args.append(tmp_source_path); test_case->compiler_args.append("--name"); test_case->compiler_args.append("test"); - test_case->compiler_args.append("--export"); - test_case->compiler_args.append("obj"); - test_case->compiler_args.append("--output"); test_case->compiler_args.append(tmp_exe_path); @@ -142,15 +137,12 @@ static void add_debug_safety_case(const char *case_name, const char *source) { test_case->source_files.at(0).relative_path = tmp_source_path; test_case->source_files.at(0).source_code = source; - test_case->compiler_args.append("build"); + test_case->compiler_args.append("build_exe"); test_case->compiler_args.append(tmp_source_path); test_case->compiler_args.append("--name"); test_case->compiler_args.append("test"); - test_case->compiler_args.append("--export"); - test_case->compiler_args.append("exe"); - test_case->compiler_args.append("--output"); test_case->compiler_args.append(tmp_exe_path); @@ -164,15 +156,12 @@ static void add_debug_safety_case(const char *case_name, const char *source) { test_case->source_files.at(0).source_code = source; test_case->output = ""; - test_case->compiler_args.append("build"); + test_case->compiler_args.append("build_exe"); test_case->compiler_args.append(tmp_source_path); test_case->compiler_args.append("--name"); test_case->compiler_args.append("test"); - test_case->compiler_args.append("--export"); - test_case->compiler_args.append("exe"); - test_case->compiler_args.append("--output"); test_case->compiler_args.append(tmp_exe_path); @@ -471,8 +460,8 @@ const foo : i32 = 0; const c = @cImport(@cInclude("stdlib.h")); export fn compare_fn(a: ?&const c_void, b: ?&const c_void) -> c_int { - const a_int = (&i32)(a ?? unreachable); - const b_int = (&i32)(b ?? unreachable); + const a_int = @bitcast(&i32, a ?? unreachable); + const b_int = @bitcast(&i32, b ?? unreachable); if (*a_int < *b_int) { -1 } else if (*a_int > *b_int) { @@ -485,7 +474,7 @@ export fn compare_fn(a: ?&const c_void, b: ?&const c_void) -> c_int { export fn main(args: c_int, argv: &&u8) -> c_int { var array = []u32 { 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 }; - c.qsort((&c_void)(&array[0]), c_ulong(array.len), @sizeOf(i32), compare_fn); + c.qsort(@bitcast(&c_void, &array[0]), c_ulong(array.len), @sizeOf(i32), compare_fn); for (array) |item, i| { if (item != i) {