diff options
37 files changed, 498 insertions, 204 deletions
diff --git a/c_headers/stdarg.h b/c_headers/stdarg.h index f6635105e0..d603d353f5 100644 --- a/c_headers/stdarg.h +++ b/c_headers/stdarg.h @@ -26,10 +26,14 @@ #ifndef __STDARG_H #define __STDARG_H +/* zig: added because macos _va_list.h was duplicately defining va_list + */ #ifndef _VA_LIST +#ifndef _VA_LIST_T typedef __builtin_va_list va_list; #define _VA_LIST #endif +#endif #define va_start(ap, param) __builtin_va_start(ap, param) #define va_end(ap) __builtin_va_end(ap) #define va_arg(ap, type) __builtin_va_arg(ap, type) diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig index af3c785c21..a4337faef3 100644 --- a/src-self-hosted/main.zig +++ b/src-self-hosted/main.zig @@ -5,6 +5,7 @@ const heap = @import("std").mem; // TODO: OutSteam and InStream interface // TODO: move allocator to heap namespace +// TODO: sync up CLI with c++ code error InvalidArgument; error MissingArg0; diff --git a/src/all_types.hpp b/src/all_types.hpp index e4d174c414..318e6b2c11 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1008,6 +1008,9 @@ struct TypeTableEntryEnum { size_t gen_union_index; size_t gen_tag_index; + + uint32_t union_size_bytes; + TypeTableEntry *most_aligned_union_member; }; struct TypeTableEntryEnumTag { @@ -1514,9 +1517,12 @@ struct CodeGen { size_t version_major; size_t version_minor; size_t version_patch; - bool verbose; + bool verbose_tokenize; + bool verbose_ast; bool verbose_link; bool verbose_ir; + bool verbose_llvm_ir; + bool verbose_cimport; ErrColor err_color; ImportTableEntry *root_import; ImportTableEntry *bootstrap_import; diff --git a/src/analyze.cpp b/src/analyze.cpp index 292943a6e6..89ce5df6b4 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -27,9 +27,17 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type); static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type); ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { - // if this assert fails, then parsec generated code that - // failed semantic analysis, which isn't supposed to happen - assert(!node->owner->c_import_node); + if (node->owner->c_import_node != nullptr) { + // if this happens, then parsec generated code that + // failed semantic analysis, which isn't supposed to happen + ErrorMsg *err = add_node_error(g, node->owner->c_import_node, + buf_sprintf("compiler bug: @cImport generated invalid zig code")); + + add_error_note(g, err, node, msg); + + g->errors.append(err); + return err; + } ErrorMsg *err = err_msg_create_with_line(node->owner->path, node->line, node->column, node->owner->source_code, node->owner->line_offsets, msg); @@ -39,9 +47,20 @@ ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { } ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg) { - // if this assert fails, then parsec generated code that - // failed semantic analysis, which isn't supposed to happen - assert(!node->owner->c_import_node); + if (node->owner->c_import_node != nullptr) { + // if this happens, then parsec generated code that + // failed semantic analysis, which isn't supposed to happen + + Buf *note_path = buf_create_from_str("?.c"); + Buf *note_source = buf_create_from_str("TODO: remember C source location to display here "); + ZigList<size_t> note_line_offsets = {0}; + note_line_offsets.append(0); + ErrorMsg *note = err_msg_create_with_line(note_path, 0, 0, + note_source, ¬e_line_offsets, msg); + + err_msg_add_note(parent_msg, note); + return note; + } ErrorMsg *err = err_msg_create_with_line(node->owner->path, node->line, node->column, node->owner->source_code, node->owner->line_offsets, msg); @@ -1344,6 +1363,8 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { // unset temporary flag enum_type->data.enumeration.embedded_in_current = false; enum_type->data.enumeration.complete = true; + enum_type->data.enumeration.union_size_bytes = biggest_size_in_bits / 8; + enum_type->data.enumeration.most_aligned_union_member = most_aligned_union_member; if (!enum_type->data.enumeration.is_invalid) { TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count); @@ -1365,10 +1386,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { }; union_type_ref = LLVMStructType(union_element_types, 2, false); } else { - LLVMTypeRef union_element_types[] = { - most_aligned_union_member->type_ref, - }; - union_type_ref = LLVMStructType(union_element_types, 1, false); + union_type_ref = most_aligned_union_member->type_ref; } enum_type->data.enumeration.union_type_ref = union_type_ref; @@ -2804,7 +2822,6 @@ static bool is_container(TypeTableEntry *type_entry) { switch (type_entry->id) { case TypeTableEntryIdInvalid: case TypeTableEntryIdVar: - case TypeTableEntryIdOpaque: zig_unreachable(); case TypeTableEntryIdStruct: case TypeTableEntryIdEnum: @@ -2831,6 +2848,7 @@ static bool is_container(TypeTableEntry *type_entry) { case TypeTableEntryIdBoundFn: case TypeTableEntryIdEnumTag: case TypeTableEntryIdArgTuple: + case TypeTableEntryIdOpaque: return false; } zig_unreachable(); @@ -2982,7 +3000,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ return; } - if (g->verbose) { + if (g->verbose_ir) { fprintf(stderr, "{ // (analyzed)\n"); ir_print(g, stderr, &fn_table_entry->analyzed_executable, 4); fprintf(stderr, "}\n"); @@ -3015,7 +3033,7 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { fn_table_entry->anal_state = FnAnalStateInvalid; return; } - if (g->verbose) { + if (g->verbose_ir) { fprintf(stderr, "\n"); ast_render(g, stderr, fn_table_entry->body_node, 4); fprintf(stderr, "\n{ // (IR)\n"); @@ -3115,7 +3133,7 @@ void preview_use_decl(CodeGen *g, AstNode *node) { } ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code) { - if (g->verbose) { + if (g->verbose_tokenize) { fprintf(stderr, "\nOriginal Source (%s):\n", buf_ptr(abs_full_path)); fprintf(stderr, "----------------\n"); fprintf(stderr, "%s\n", buf_ptr(source_code)); @@ -3135,7 +3153,7 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *a exit(1); } - if (g->verbose) { + if (g->verbose_tokenize) { print_tokens(source_code, tokenization.tokens); fprintf(stderr, "\nAST:\n"); @@ -3150,7 +3168,7 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *a import_entry->root = ast_parse(source_code, tokenization.tokens, import_entry, g->err_color); assert(import_entry->root); - if (g->verbose) { + if (g->verbose_ast) { ast_print(stderr, import_entry->root, 0); } diff --git a/src/codegen.cpp b/src/codegen.cpp index 61640b062b..1dc8205c8e 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -196,10 +196,6 @@ void codegen_set_is_static(CodeGen *g, bool is_static) { g->is_static = is_static; } -void codegen_set_verbose(CodeGen *g, bool verbose) { - g->verbose = verbose; -} - void codegen_set_each_lib_rpath(CodeGen *g, bool each_lib_rpath) { g->each_lib_rpath = each_lib_rpath; } @@ -452,10 +448,10 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { LLVMSetLinkage(fn_table_entry->llvm_value, LLVMExternalLinkage); break; case GlobalLinkageIdWeak: - LLVMSetLinkage(fn_table_entry->llvm_value, LLVMWeakAnyLinkage); + LLVMSetLinkage(fn_table_entry->llvm_value, LLVMWeakODRLinkage); break; case GlobalLinkageIdLinkOnce: - LLVMSetLinkage(fn_table_entry->llvm_value, LLVMLinkOnceAnyLinkage); + LLVMSetLinkage(fn_table_entry->llvm_value, LLVMLinkOnceODRLinkage); break; } @@ -3665,6 +3661,12 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con zig_unreachable(); } +// We have this because union constants can't be represented by the official union type, +// and this property bubbles up in whatever aggregate type contains a union constant +static bool is_llvm_value_unnamed_type(TypeTableEntry *type_entry, LLVMValueRef val) { + return LLVMTypeOf(val) != type_entry->type_ref; +} + static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { TypeTableEntry *type_entry = const_val->type; assert(!type_entry->zero_bits); @@ -3726,24 +3728,34 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { } else { LLVMValueRef child_val; LLVMValueRef maybe_val; + bool make_unnamed_struct; if (const_val->data.x_maybe) { child_val = gen_const_val(g, const_val->data.x_maybe); maybe_val = LLVMConstAllOnes(LLVMInt1Type()); + + make_unnamed_struct = is_llvm_value_unnamed_type(const_val->type, child_val); } else { - child_val = LLVMConstNull(child_type->type_ref); + child_val = LLVMGetUndef(child_type->type_ref); maybe_val = LLVMConstNull(LLVMInt1Type()); + + make_unnamed_struct = false; } LLVMValueRef fields[] = { child_val, maybe_val, }; - return LLVMConstStruct(fields, 2, false); + if (make_unnamed_struct) { + return LLVMConstStruct(fields, 2, false); + } else { + return LLVMConstNamedStruct(type_entry->type_ref, fields, 2); + } } } case TypeTableEntryIdStruct: { LLVMValueRef *fields = allocate<LLVMValueRef>(type_entry->data.structure.gen_field_count); size_t src_field_count = type_entry->data.structure.src_field_count; + bool make_unnamed_struct = false; if (type_entry->data.structure.layout == ContainerLayoutPacked) { size_t src_field_index = 0; while (src_field_index < src_field_count) { @@ -3761,8 +3773,10 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { } if (src_field_index + 1 == src_field_index_end) { - fields[type_struct_field->gen_index] = - gen_const_val(g, &const_val->data.x_struct.fields[src_field_index]); + ConstExprValue *field_val = &const_val->data.x_struct.fields[src_field_index]; + LLVMValueRef val = gen_const_val(g, field_val); + fields[type_struct_field->gen_index] = val; + make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(field_val->type, val); } else { LLVMTypeRef big_int_type_ref = LLVMStructGetTypeAtIndex(type_entry->type_ref, (unsigned)type_struct_field->gen_index); @@ -3790,11 +3804,18 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { if (type_struct_field->gen_index == SIZE_MAX) { continue; } - fields[type_struct_field->gen_index] = gen_const_val(g, &const_val->data.x_struct.fields[i]); + ConstExprValue *field_val = &const_val->data.x_struct.fields[i]; + LLVMValueRef val = gen_const_val(g, field_val); + fields[type_struct_field->gen_index] = val; + make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(field_val->type, val); } } - return LLVMConstStruct(fields, type_entry->data.structure.gen_field_count, - type_entry->data.structure.layout == ContainerLayoutPacked); + if (make_unnamed_struct) { + return LLVMConstStruct(fields, type_entry->data.structure.gen_field_count, + type_entry->data.structure.layout == ContainerLayoutPacked); + } else { + return LLVMConstNamedStruct(type_entry->type_ref, fields, type_entry->data.structure.gen_field_count); + } } case TypeTableEntryIdUnion: { @@ -3808,11 +3829,19 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { } LLVMValueRef *values = allocate<LLVMValueRef>(len); + LLVMTypeRef element_type_ref = type_entry->data.array.child_type->type_ref; + bool make_unnamed_struct = false; for (uint64_t i = 0; i < len; i += 1) { ConstExprValue *elem_value = &const_val->data.x_array.s_none.elements[i]; - values[i] = gen_const_val(g, elem_value); + LLVMValueRef val = gen_const_val(g, elem_value); + values[i] = val; + make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(elem_value->type, val); + } + if (make_unnamed_struct) { + return LLVMConstStruct(values, len, true); + } else { + return LLVMConstArray(element_type_ref, values, (unsigned)len); } - return LLVMConstArray(LLVMTypeOf(values[0]), values, (unsigned)len); } case TypeTableEntryIdEnum: { @@ -3825,14 +3854,20 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { TypeEnumField *enum_field = &type_entry->data.enumeration.fields[const_val->data.x_enum.tag]; assert(enum_field->value == const_val->data.x_enum.tag); LLVMValueRef union_value; + + bool make_unnamed_struct; + if (type_has_bits(enum_field->type_entry)) { - uint64_t union_type_bytes = LLVMStoreSizeOfType(g->target_data_ref, - union_type_ref); uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref, enum_field->type_entry->type_ref); - uint64_t pad_bytes = union_type_bytes - field_type_bytes; + uint64_t pad_bytes = type_entry->data.enumeration.union_size_bytes - field_type_bytes; + + ConstExprValue *payload_value = const_val->data.x_enum.payload; + LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value); + + make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) || + payload_value->type != type_entry->data.enumeration.most_aligned_union_member; - LLVMValueRef correctly_typed_value = gen_const_val(g, const_val->data.x_enum.payload); if (pad_bytes == 0) { union_value = correctly_typed_value; } else { @@ -3843,12 +3878,18 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { union_value = LLVMConstStruct(fields, 2, false); } } else { + make_unnamed_struct = false; union_value = LLVMGetUndef(union_type_ref); } LLVMValueRef fields[2]; fields[type_entry->data.enumeration.gen_tag_index] = tag_value; fields[type_entry->data.enumeration.gen_union_index] = union_value; - return LLVMConstStruct(fields, 2, false); + + if (make_unnamed_struct) { + return LLVMConstStruct(fields, 2, false); + } else { + return LLVMConstNamedStruct(type_entry->type_ref, fields, 2); + } } } case TypeTableEntryIdFn: @@ -3932,18 +3973,26 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { } else { LLVMValueRef err_tag_value; LLVMValueRef err_payload_value; + bool make_unnamed_struct; if (const_val->data.x_err_union.err) { err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, const_val->data.x_err_union.err->value, false); err_payload_value = LLVMConstNull(child_type->type_ref); + make_unnamed_struct = false; } else { err_tag_value = LLVMConstNull(g->err_tag_type->type_ref); - err_payload_value = gen_const_val(g, const_val->data.x_err_union.payload); + ConstExprValue *payload_val = const_val->data.x_err_union.payload; + err_payload_value = gen_const_val(g, payload_val); + make_unnamed_struct = is_llvm_value_unnamed_type(payload_val->type, err_payload_value); } LLVMValueRef fields[] = { err_tag_value, err_payload_value, }; - return LLVMConstStruct(fields, 2, false); + if (make_unnamed_struct) { + return LLVMConstStruct(fields, 2, false); + } else { + return LLVMConstNamedStruct(type_entry->type_ref, fields, 2); + } } } case TypeTableEntryIdVoid: @@ -4159,10 +4208,6 @@ static void validate_inline_fns(CodeGen *g) { } static void do_code_gen(CodeGen *g) { - if (g->verbose) { - fprintf(stderr, "\nCode Generation:\n"); - fprintf(stderr, "------------------\n"); - } assert(!g->errors.length); codegen_add_time_event(g, "Code Generation"); @@ -4439,7 +4484,8 @@ static void do_code_gen(CodeGen *g) { ZigLLVMDIBuilderFinalize(g->dbuilder); - if (g->verbose || g->verbose_ir) { + if (g->verbose_llvm_ir) { + fflush(stderr); LLVMDumpModule(g->module); } @@ -5269,10 +5315,6 @@ static void gen_root_source(CodeGen *g) { resolve_top_level_decl(g, panic_tld, false, nullptr); } - if (g->verbose) { - fprintf(stderr, "\nIR Generation and Semantic Analysis:\n"); - fprintf(stderr, "--------------------------------------\n"); - } if (!g->error_during_imports) { semantic_analyze(g); } @@ -5286,9 +5328,6 @@ static void gen_root_source(CodeGen *g) { } report_errors_and_maybe_exit(g); - if (g->verbose) { - fprintf(stderr, "OK\n"); - } } diff --git a/src/codegen.hpp b/src/codegen.hpp index 35ae31d8b9..5c54e9bce8 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -25,7 +25,6 @@ void codegen_set_each_lib_rpath(CodeGen *codegen, bool each_lib_rpath); void codegen_set_is_static(CodeGen *codegen, bool is_static); void codegen_set_strip(CodeGen *codegen, bool strip); -void codegen_set_verbose(CodeGen *codegen, bool verbose); void codegen_set_errmsg_color(CodeGen *codegen, ErrColor err_color); void codegen_set_out_name(CodeGen *codegen, Buf *out_name); void codegen_set_libc_lib_dir(CodeGen *codegen, Buf *libc_lib_dir); diff --git a/src/config.h.in b/src/config.h.in index 36bd66098b..a596213a3d 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -20,7 +20,6 @@ #define ZIG_DYNAMIC_LINKER "@ZIG_DYNAMIC_LINKER@" #cmakedefine ZIG_EACH_LIB_RPATH -#cmakedefine ZIG_LLVM_OLD_CXX_ABI // Only used for running tests before installing. #define ZIG_TEST_DIR "@CMAKE_SOURCE_DIR@/test" diff --git a/src/errmsg.cpp b/src/errmsg.cpp index bef4d7548d..01c3ee8429 100644 --- a/src/errmsg.cpp +++ b/src/errmsg.cpp @@ -123,6 +123,7 @@ ErrorMsg *err_msg_create_with_line(Buf *path, size_t line, size_t column, size_t end_line = line + 1; size_t line_end_offset = (end_line >= line_offsets->length) ? buf_len(source) : line_offsets->at(line + 1); size_t len = (line_end_offset + 1 > line_start_offset) ? (line_end_offset - line_start_offset - 1) : 0; + if (len == SIZE_MAX) len = 0; buf_init_from_mem(&err_msg->line_buf, buf_ptr(source) + line_start_offset, len); diff --git a/src/ir.cpp b/src/ir.cpp index 0879942b3e..6c6ce676f6 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -7849,7 +7849,7 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node if (ir_executable.invalid) return codegen->invalid_instruction; - if (codegen->verbose) { + if (codegen->verbose_ir) { fprintf(stderr, "\nSource: "); ast_render(codegen, stderr, node, 4); fprintf(stderr, "\n{ // (IR)\n"); @@ -7870,7 +7870,7 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node if (type_is_invalid(result_type)) return codegen->invalid_instruction; - if (codegen->verbose) { + if (codegen->verbose_ir) { fprintf(stderr, "{ // (analyzed)\n"); ir_print(codegen, stderr, &analyzed_executable, 4); fprintf(stderr, "}\n"); @@ -13514,7 +13514,7 @@ static TypeTableEntry *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruc return ira->codegen->builtin_types.entry_invalid; } - if (ira->codegen->verbose) { + if (ira->codegen->verbose_cimport) { fprintf(stderr, "\nC imports:\n"); fprintf(stderr, "-----------\n"); ast_render(ira->codegen, stderr, child_import->root, 4); @@ -15312,6 +15312,11 @@ static TypeTableEntry *ir_analyze_instruction_set_align_stack(IrAnalyze *ira, Ir if (!ir_resolve_align(ira, align_bytes_inst, &align_bytes)) return ira->codegen->builtin_types.entry_invalid; + if (align_bytes > 256) { + ir_add_error(ira, &instruction->base, buf_sprintf("attempt to @setAlignStack(%" PRIu32 "); maximum is 256", align_bytes)); + return ira->codegen->builtin_types.entry_invalid; + } + FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); if (fn_entry == nullptr) { ir_add_error(ira, &instruction->base, buf_sprintf("@setAlignStack outside function")); diff --git a/src/link.cpp b/src/link.cpp index f2f21fd746..a4e5b2dd25 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -37,7 +37,12 @@ static Buf *build_o_raw(CodeGen *parent_gen, const char *oname, Buf *full_path) parent_gen->zig_lib_dir); child_gen->want_h_file = false; + child_gen->verbose_tokenize = parent_gen->verbose_tokenize; + child_gen->verbose_ast = parent_gen->verbose_ast; child_gen->verbose_link = parent_gen->verbose_link; + child_gen->verbose_ir = parent_gen->verbose_ir; + child_gen->verbose_llvm_ir = parent_gen->verbose_llvm_ir; + child_gen->verbose_cimport = parent_gen->verbose_cimport; codegen_set_cache_dir(child_gen, parent_gen->cache_dir); @@ -46,7 +51,6 @@ static Buf *build_o_raw(CodeGen *parent_gen, const char *oname, Buf *full_path) codegen_set_out_name(child_gen, buf_create_from_str(oname)); - codegen_set_verbose(child_gen, parent_gen->verbose); codegen_set_errmsg_color(child_gen, parent_gen->err_color); codegen_set_mmacosx_version_min(child_gen, parent_gen->mmacosx_version_min); @@ -858,15 +862,12 @@ void codegen_link(CodeGen *g, const char *out_file) { buf_resize(&lj.out_file, 0); } - if (g->verbose || g->verbose_ir) { + if (g->verbose_llvm_ir) { fprintf(stderr, "\nOptimization:\n"); fprintf(stderr, "---------------\n"); + fflush(stderr); LLVMDumpModule(g->module); } - if (g->verbose || g->verbose_link) { - fprintf(stderr, "\nLink:\n"); - fprintf(stderr, "-------\n"); - } bool override_out_file = (buf_len(&lj.out_file) != 0); if (!override_out_file) { @@ -887,9 +888,6 @@ void codegen_link(CodeGen *g, const char *out_file) { zig_panic("unable to rename object file into final output: %s", err_str(err)); } } - if (g->verbose || g->verbose_link) { - fprintf(stderr, "OK\n"); - } return; } @@ -907,7 +905,7 @@ void codegen_link(CodeGen *g, const char *out_file) { construct_linker_job(&lj); - if (g->verbose || g->verbose_link) { + if (g->verbose_link) { for (size_t i = 0; i < lj.args.length; i += 1) { const char *space = (i != 0) ? " " : ""; fprintf(stderr, "%s%s", space, lj.args.at(i)); @@ -924,8 +922,4 @@ void codegen_link(CodeGen *g, const char *out_file) { } codegen_add_time_event(g, "Done"); - - if (g->verbose || g->verbose_link) { - fprintf(stderr, "OK\n"); - } } diff --git a/src/main.cpp b/src/main.cpp index a4aa00aeca..358f1cf255 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,66 +20,69 @@ static int usage(const char *arg0) { fprintf(stderr, "Usage: %s [command] [options]\n" "Commands:\n" " build build project from build.zig\n" - " build-exe [source] create executable from source or object files\n" - " build-lib [source] create library from source or object files\n" - " build-obj [source] create object from source or assembly\n" - " parsec [source] convert c code to zig code\n" + " build-exe $source create executable from source or object files\n" + " build-lib $source create library from source or object files\n" + " build-obj $source create object from source or assembly\n" + " parsec $source convert c code to zig code\n" " targets list available compilation targets\n" - " test [source] create and run a test build\n" + " test $source create and run a test build\n" " version print version number and exit\n" " zen print zen of zig and exit\n" "Compile Options:\n" - " --assembly [source] add assembly file to build\n" - " --cache-dir [path] override the cache directory\n" - " --color [auto|off|on] enable or disable colored error messages\n" + " --assembly $source add assembly file to build\n" + " --cache-dir $path override the cache directory\n" + " --color $auto|off|on enable or disable colored error messages\n" " --enable-timing-info print timing diagnostics\n" - " --libc-include-dir [path] directory where libc stdlib.h resides\n" - " --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" + " --libc-include-dir $path directory where libc stdlib.h resides\n" + " --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-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" " --static output will be statically linked\n" " --strip exclude debug symbols\n" - " --target-arch [name] specify target architecture\n" - " --target-environ [name] specify target environment\n" - " --target-os [name] specify target operating system\n" - " --verbose turn on compiler debug output\n" - " --verbose-link turn on compiler debug output for linking only\n" - " --verbose-ir turn on compiler debug output for IR only\n" - " --zig-install-prefix [path] override directory where zig thinks it is installed\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" + " --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" + " --zig-install-prefix $path override directory where zig thinks it is installed\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" "Link Options:\n" - " --ar-path [path] set the path to ar\n" - " --dynamic-linker [path] set the path to ld.so\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" - " --libc-static-lib-dir [path] directory where libc crtbegin.o resides\n" - " --msvc-lib-dir [path] (windows) directory where vcruntime.lib resides\n" - " --kernel32-lib-dir [path] (windows) directory where kernel32.lib 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" - " --object [obj] add object file to build\n" - " -L[dir] alias for --library-path\n" + " --libc-lib-dir $path directory where libc crt1.o resides\n" + " --libc-static-lib-dir $path directory where libc crtbegin.o resides\n" + " --msvc-lib-dir $path (windows) directory where vcruntime.lib resides\n" + " --kernel32-lib-dir $path (windows) directory where kernel32.lib 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" + " --object $obj add object file to build\n" + " -L$dir alias for --library-path\n" " -rdynamic add all symbols to the dynamic symbol table\n" - " -rpath [path] add directory to the runtime library search path\n" + " -rpath $path add directory to the runtime library search path\n" " -mconsole (windows) --subsystem console to the linker\n" " -mwindows (windows) --subsystem windows to the linker\n" - " -framework [name] (darwin) link against framework\n" - " -mios-version-min [ver] (darwin) set iOS deployment target\n" - " -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target\n" - " --ver-major [ver] dynamic library semver major version\n" - " --ver-minor [ver] dynamic library semver minor version\n" - " --ver-patch [ver] dynamic library semver patch version\n" + " -framework $name (darwin) link against framework\n" + " -mios-version-min $ver (darwin) set iOS deployment target\n" + " -mmacosx-version-min $ver (darwin) set Mac OS X deployment target\n" + " --ver-major $ver dynamic library semver major version\n" + " --ver-minor $ver dynamic library semver minor version\n" + " --ver-patch $ver dynamic library semver patch version\n" "Test Options:\n" - " --test-filter [text] skip tests that do not match filter\n" - " --test-name-prefix [text] add prefix to all tests\n" - " --test-cmd [arg] specify test execution command one arg at a time\n" + " --test-filter $text skip tests that do not match filter\n" + " --test-name-prefix $text add prefix to all tests\n" + " --test-cmd $arg specify test execution command one arg at a time\n" " --test-cmd-bin appends test binary path to test cmd args\n" , arg0); return EXIT_FAILURE; @@ -273,9 +276,12 @@ int main(int argc, char **argv) { bool is_static = false; OutType out_type = OutTypeUnknown; const char *out_name = nullptr; - bool verbose = false; + bool verbose_tokenize = false; + bool verbose_ast = false; bool verbose_link = false; bool verbose_ir = false; + bool verbose_llvm_ir = false; + bool verbose_cimport = false; ErrColor color = ErrColorAuto; const char *libc_lib_dir = nullptr; const char *libc_static_lib_dir = nullptr; @@ -326,9 +332,7 @@ int main(int argc, char **argv) { args.append(NULL); // placeholder args.append(NULL); // placeholder for (int i = 2; i < argc; i += 1) { - if (strcmp(argv[i], "--debug-build-verbose") == 0) { - verbose = true; - } else if (strcmp(argv[i], "--help") == 0) { + if (strcmp(argv[i], "--help") == 0) { asked_for_help = true; args.append(argv[i]); } else if (i + 1 < argc && strcmp(argv[i], "--build-file") == 0) { @@ -361,7 +365,6 @@ int main(int argc, char **argv) { CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe, BuildModeDebug, zig_lib_dir_buf); codegen_set_out_name(g, buf_create_from_str("build")); - codegen_set_verbose(g, verbose); Buf build_file_abs = BUF_INIT; os_path_resolve(buf_create_from_str("."), buf_create_from_str(build_file), &build_file_abs); @@ -396,14 +399,30 @@ int main(int argc, char **argv) { "\n" "General Options:\n" " --help Print this help and exit\n" - " --build-file [file] Override path to build.zig\n" - " --cache-dir [path] Override path to cache directory\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" - " --debug-build-verbose Print verbose debugging information for the build system itself\n" - " --prefix [prefix] Override default install prefix\n" + " --verbose-tokenize Enable compiler debug output for tokenization\n" + " --verbose-ast Enable compiler debug output for parsing into an AST\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" + " --prefix $path Override default install prefix\n" "\n" - "More options become available when the build file is found.\n" + "Project-specific options become available when the build file is found.\n" "Run this command with no options to generate a build.zig template.\n" + "\n" + "Advanced Options:\n" + " --build-file $file Override path to build.zig\n" + " --cache-dir $path Override path to cache directory\n" + " --verbose-tokenize Enable compiler debug output for tokenization\n" + " --verbose-ast Enable compiler debug output for parsing into an AST\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" + "\n" , zig_exe_path); return 0; } @@ -450,12 +469,18 @@ int main(int argc, char **argv) { strip = true; } else if (strcmp(arg, "--static") == 0) { is_static = true; - } else if (strcmp(arg, "--verbose") == 0) { - verbose = true; + } else if (strcmp(arg, "--verbose-tokenize") == 0) { + verbose_tokenize = true; + } else if (strcmp(arg, "--verbose-ast") == 0) { + verbose_ast = true; } else if (strcmp(arg, "--verbose-link") == 0) { verbose_link = true; } else if (strcmp(arg, "--verbose-ir") == 0) { verbose_ir = true; + } else if (strcmp(arg, "--verbose-llvm-ir") == 0) { + verbose_llvm_ir = true; + } else if (strcmp(arg, "--verbose-cimport") == 0) { + verbose_cimport = true; } else if (strcmp(arg, "-mwindows") == 0) { mwindows = true; } else if (strcmp(arg, "-mconsole") == 0) { @@ -738,9 +763,12 @@ int main(int argc, char **argv) { codegen_set_kernel32_lib_dir(g, buf_create_from_str(kernel32_lib_dir)); if (dynamic_linker) codegen_set_dynamic_linker(g, buf_create_from_str(dynamic_linker)); - codegen_set_verbose(g, verbose); + g->verbose_tokenize = verbose_tokenize; + g->verbose_ast = verbose_ast; g->verbose_link = verbose_link; g->verbose_ir = verbose_ir; + g->verbose_llvm_ir = verbose_llvm_ir; + g->verbose_cimport = verbose_cimport; codegen_set_errmsg_color(g, color); for (size_t i = 0; i < lib_dirs.length; i += 1) { diff --git a/src/parsec.cpp b/src/parsec.cpp index d200c0531d..586e95bc75 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -3167,7 +3167,7 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const ch { Context context = {0}; Context *c = &context; - c->warnings_on = codegen->verbose; + c->warnings_on = codegen->verbose_cimport; c->import = import; c->errors = errors; if (buf_ends_with_str(buf_create_from_str(target_file), ".h")) { diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index d277fb2502..77d74c52ee 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -416,6 +416,44 @@ static void handle_string_escape(Tokenize *t, uint8_t c) { } } +static const char* get_escape_shorthand(uint8_t c) { + switch (c) { + case '\0': + return "\\0"; + case '\a': + return "\\a"; + case '\b': + return "\\b"; + case '\t': + return "\\t"; + case '\n': + return "\\n"; + case '\v': + return "\\v"; + case '\f': + return "\\f"; + case '\r': + return "\\r"; + default: + return nullptr; + } +} + +static void invalid_char_error(Tokenize *t, uint8_t c) { + if (c == '\r') { + tokenize_error(t, "invalid carriage return, only '\\n' line endings are supported"); + } else if (isprint(c)) { + tokenize_error(t, "invalid character: '%c'", c); + } else { + const char *sh = get_escape_shorthand(c); + if (sh) { + tokenize_error(t, "invalid character: '%s'", sh); + } else { + tokenize_error(t, "invalid character: '\\x%x'", c); + } + } +} + void tokenize(Buf *buf, Tokenization *out) { Tokenize t = {0}; t.out = out; @@ -580,7 +618,7 @@ void tokenize(Buf *buf, Tokenization *out) { t.state = TokenizeStateSawQuestionMark; break; default: - tokenize_error(&t, "invalid character: '%c'", c); + invalid_char_error(&t, c); } break; case TokenizeStateSawQuestionMark: @@ -890,7 +928,7 @@ void tokenize(Buf *buf, Tokenization *out) { t.state = TokenizeStateLineString; break; default: - tokenize_error(&t, "invalid character: '%c'", c); + invalid_char_error(&t, c); break; } break; @@ -919,7 +957,7 @@ void tokenize(Buf *buf, Tokenization *out) { break; case '\\': if (t.cur_tok->data.str_lit.is_c_str) { - tokenize_error(&t, "invalid character: '%c'", c); + invalid_char_error(&t, c); } t.state = TokenizeStateLineStringContinue; break; @@ -949,7 +987,7 @@ void tokenize(Buf *buf, Tokenization *out) { buf_append_char(&t.cur_tok->data.str_lit.str, '\n'); break; default: - tokenize_error(&t, "invalid character: '%c'", c); + invalid_char_error(&t, c); break; } break; @@ -1073,7 +1111,7 @@ void tokenize(Buf *buf, Tokenization *out) { handle_string_escape(&t, '\"'); break; default: - tokenize_error(&t, "invalid character: '%c'", c); + invalid_char_error(&t, c); } break; case TokenizeStateCharCode: @@ -1147,7 +1185,7 @@ void tokenize(Buf *buf, Tokenization *out) { t.state = TokenizeStateStart; break; default: - tokenize_error(&t, "invalid character: '%c'", c); + invalid_char_error(&t, c); } break; case TokenizeStateZero: @@ -1189,7 +1227,7 @@ void tokenize(Buf *buf, Tokenization *out) { uint32_t digit_value = get_digit_value(c); if (digit_value >= t.radix) { if (is_symbol_char(c)) { - tokenize_error(&t, "invalid character: '%c'", c); + invalid_char_error(&t, c); } // not my char t.pos -= 1; @@ -1233,7 +1271,7 @@ void tokenize(Buf *buf, Tokenization *out) { uint32_t digit_value = get_digit_value(c); if (digit_value >= t.radix) { if (is_symbol_char(c)) { - tokenize_error(&t, "invalid character: '%c'", c); + invalid_char_error(&t, c); } // not my char t.pos -= 1; @@ -1282,7 +1320,7 @@ void tokenize(Buf *buf, Tokenization *out) { uint32_t digit_value = get_digit_value(c); if (digit_value >= t.radix) { if (is_symbol_char(c)) { - tokenize_error(&t, "invalid character: '%c'", c); + invalid_char_error(&t, c); } // not my char t.pos -= 1; diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index f82b1d5423..0e1a067bc6 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -5,15 +5,6 @@ * See http://opensource.org/licenses/MIT */ -// This must go before all includes. -#include "config.h" -#if defined(ZIG_LLVM_OLD_CXX_ABI) -#define _GLIBCXX_USE_CXX11_ABI 0 -#endif - - -#include "zig_llvm.hpp" - /* * The point of this file is to contain all the LLVM C++ API interaction so that: @@ -22,6 +13,8 @@ * 3. Prevent C++ from infecting the rest of the project. */ +#include "zig_llvm.hpp" + #include <llvm/Analysis/TargetLibraryInfo.h> #include <llvm/Analysis/TargetTransformInfo.h> #include <llvm/IR/DIBuilder.h> diff --git a/std/build.zig b/std/build.zig index 84eba6d33b..7cf2ac5987 100644 --- a/std/build.zig +++ b/std/build.zig @@ -33,6 +33,12 @@ pub const Builder = struct { available_options_map: AvailableOptionsMap, available_options_list: ArrayList(AvailableOption), verbose: bool, + verbose_tokenize: bool, + verbose_ast: bool, + verbose_link: bool, + verbose_ir: bool, + verbose_llvm_ir: bool, + verbose_cimport: bool, invalid_user_input: bool, zig_exe: []const u8, default_step: &Step, @@ -88,6 +94,12 @@ pub const Builder = struct { .build_root = build_root, .cache_root = %%os.path.relative(allocator, build_root, cache_root), .verbose = false, + .verbose_tokenize = false, + .verbose_ast = false, + .verbose_link = false, + .verbose_ir = false, + .verbose_llvm_ir = false, + .verbose_cimport = false, .invalid_user_input = false, .allocator = allocator, .lib_paths = ArrayList([]const u8).init(allocator), @@ -536,15 +548,19 @@ pub const Builder = struct { return self.spawnChildEnvMap(null, &self.env_map, argv); } + fn printCmd(cwd: ?[]const u8, argv: []const []const u8) { + if (cwd) |yes_cwd| %%io.stderr.print("cd {} && ", yes_cwd); + for (argv) |arg| { + %%io.stderr.print("{} ", arg); + } + %%io.stderr.printf("\n"); + } + fn spawnChildEnvMap(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap, argv: []const []const u8) -> %void { if (self.verbose) { - if (cwd) |yes_cwd| %%io.stderr.print("cd {}; ", yes_cwd); - for (argv) |arg| { - %%io.stderr.print("{} ", arg); - } - %%io.stderr.printf("\n"); + printCmd(cwd, argv); } const child = %%os.ChildProcess.init(argv, self.allocator); @@ -561,12 +577,15 @@ pub const Builder = struct { switch (term) { Term.Exited => |code| { if (code != 0) { - %%io.stderr.printf("Process {} exited with error code {}\n", argv[0], code); + %%io.stderr.printf("The following command exited with error code {}:\n", code); + printCmd(cwd, argv); return error.UncleanExit; } }, else => { - %%io.stderr.printf("Process {} terminated unexpectedly\n", argv[0]); + %%io.stderr.printf("The following command terminated unexpectedly:\n"); + printCmd(cwd, argv); + return error.UncleanExit; }, }; @@ -1117,6 +1136,12 @@ pub const LibExeObjStep = struct { if (self.verbose) { %%zig_args.append("--verbose"); } + if (builder.verbose_tokenize) %%zig_args.append("--verbose-tokenize"); + if (builder.verbose_ast) %%zig_args.append("--verbose-ast"); + if (builder.verbose_cimport) %%zig_args.append("--verbose-cimport"); + if (builder.verbose_ir) %%zig_args.append("--verbose-ir"); + if (builder.verbose_llvm_ir) %%zig_args.append("--verbose-llvm-ir"); + if (builder.verbose_link) %%zig_args.append("--verbose-link"); if (self.strip) { %%zig_args.append("--strip"); diff --git a/std/fmt/errol/index.zig b/std/fmt/errol/index.zig index ac9f6b0c64..0a1ea7deef 100644 --- a/std/fmt/errol/index.zig +++ b/std/fmt/errol/index.zig @@ -32,13 +32,13 @@ pub fn errol3(value: f64, buffer: []u8) -> FloatDecimal { fn errol3u(val: f64, buffer: []u8) -> FloatDecimal { // check if in integer or fixed range - if (val >= 9.007199254740992e15 and val < 3.40282366920938e+38) { + if (val > 9.007199254740992e15 and val < 3.40282366920938e+38) { return errolInt(val, buffer); } else if (val >= 16.0 and val < 9.007199254740992e15) { return errolFixed(val, buffer); } - + // normalize the midpoint const e = math.frexp(val).exponent; @@ -138,7 +138,7 @@ fn tableLowerBound(k: u64) -> usize { while (j < enum3.len) { if (enum3[j] < k) { - j = 2 * k + 2; + j = 2 * j + 2; } else { i = j; j = 2 * j + 1; @@ -217,7 +217,7 @@ fn hpMul10(hp: &HP) { hp.val *= 10.0; hp.off *= 10.0; - + var off = hp.val; off -= val * 8.0; off -= val * 2.0; @@ -235,13 +235,13 @@ fn hpMul10(hp: &HP) { fn errolInt(val: f64, buffer: []u8) -> FloatDecimal { const pow19 = u128(1e19); - assert((val >= 9.007199254740992e15) and val < (3.40282366920938e38)); + assert((val > 9.007199254740992e15) and val < (3.40282366920938e38)); var mid = u128(val); var low: u128 = mid - fpeint((fpnext(val) - val) / 2.0); var high: u128 = mid + fpeint((val - fpprev(val)) / 2.0); - if (@bitCast(u64, val) & 0x1 != 0) { + if (@bitCast(u64, val) & 0x1 != 0) { high -= 1; } else { low -= 1; @@ -347,11 +347,11 @@ fn errolFixed(val: f64, buffer: []u8) -> FloatDecimal { } fn fpnext(val: f64) -> f64 { - return @bitCast(f64, @bitCast(u64, val) + 1); + return @bitCast(f64, @bitCast(u64, val) +% 1); } fn fpprev(val: f64) -> f64 { - return @bitCast(f64, @bitCast(u64, val) - 1); + return @bitCast(f64, @bitCast(u64, val) -% 1); } pub const c_digits_lut = []u8 { @@ -510,10 +510,6 @@ fn u64toa(value_param: u64, buffer: []u8) -> usize { buf_index += 1; buffer[buf_index] = c_digits_lut[d8]; buf_index += 1; - buffer[buf_index] = c_digits_lut[d8]; - buf_index += 1; - buffer[buf_index] = c_digits_lut[d8]; - buf_index += 1; buffer[buf_index] = c_digits_lut[d8 + 1]; buf_index += 1; } else { @@ -613,7 +609,7 @@ fn fpeint(from: f64) -> u128 { const bits = @bitCast(u64, from); assert((bits & ((1 << 52) - 1)) == 0); - return u64(1) << u6(((bits >> 52) - 1023)); + return u128(1) << @truncate(u7, (bits >> 52) -% 1023); } diff --git a/std/fmt/index.zig b/std/fmt/index.zig index b378afa1b0..56b9a2e960 100644 --- a/std/fmt/index.zig +++ b/std/fmt/index.zig @@ -244,30 +244,47 @@ pub fn formatBuf(buf: []const u8, width: usize, } pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []const u8)->bool) -> bool { - var buffer: [20]u8 = undefined; - const float_decimal = errol3(f64(value), buffer[0..]); - if (float_decimal.exp != 0) { - if (!output(context, float_decimal.digits[0..1])) - return false; - } else { - if (!output(context, "0")) + var x = f64(value); + + // Errol doesn't handle these special cases. + if (math.isNan(x)) { + return output(context, "NaN"); + } + if (math.signbit(x)) { + if (!output(context, "-")) return false; + x = -x; } + if (math.isPositiveInf(x)) { + return output(context, "Infinity"); + } + if (x == 0.0) { + return output(context, "0.0"); + } + + var buffer: [32]u8 = undefined; + const float_decimal = errol3(x, buffer[0..]); + if (!output(context, float_decimal.digits[0..1])) + return false; if (!output(context, ".")) return false; if (float_decimal.digits.len > 1) { - const start = if (float_decimal.exp == 0) usize(0) else usize(1); - if (!output(context, float_decimal.digits[start .. math.min(usize(7), float_decimal.digits.len)])) + const num_digits = if (@typeOf(value) == f32) { + math.min(usize(9), float_decimal.digits.len) + } else { + float_decimal.digits.len + }; + if (!output(context, float_decimal.digits[1 .. num_digits])) return false; } else { if (!output(context, "0")) return false; } - if (float_decimal.exp != 1 and float_decimal.exp != 0) { + if (float_decimal.exp != 1) { if (!output(context, "e")) return false; - if (!formatInt(float_decimal.exp, 10, false, 0, context, output)) + if (!formatInt(float_decimal.exp - 1, 10, false, 0, context, output)) return false; } return true; @@ -514,6 +531,38 @@ test "fmt.format" { const result = bufPrint(buf1[0..], "u3: {}\n", value); assert(mem.eql(u8, result, "u3: 5\n")); } + + // TODO get these tests passing in release modes + // https://github.com/zig-lang/zig/issues/564 + if (builtin.mode == builtin.Mode.Debug) { + { + var buf1: [32]u8 = undefined; + const value: f32 = 12.34; + const result = bufPrint(buf1[0..], "f32: {}\n", value); + assert(mem.eql(u8, result, "f32: 1.23400001e1\n")); + } + { + var buf1: [32]u8 = undefined; + const value: f64 = -12.34e10; + const result = bufPrint(buf1[0..], "f64: {}\n", value); + assert(mem.eql(u8, result, "f64: -1.234e11\n")); + } + { + var buf1: [32]u8 = undefined; + const result = bufPrint(buf1[0..], "f64: {}\n", math.nan_f64); + assert(mem.eql(u8, result, "f64: NaN\n")); + } + { + var buf1: [32]u8 = undefined; + const result = bufPrint(buf1[0..], "f64: {}\n", math.inf_f64); + assert(mem.eql(u8, result, "f64: Infinity\n")); + } + { + var buf1: [32]u8 = undefined; + const result = bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64); + assert(mem.eql(u8, result, "f64: -Infinity\n")); + } + } } pub fn trim(buf: []const u8) -> []const u8 { diff --git a/std/special/build_runner.zig b/std/special/build_runner.zig index b1fbfc6c2b..089137c923 100644 --- a/std/special/build_runner.zig +++ b/std/special/build_runner.zig @@ -69,6 +69,18 @@ pub fn main() -> %void { %%io.stderr.printf("Expected argument after --prefix\n\n"); return usage(&builder, false, &io.stderr); }); + } else if (mem.eql(u8, arg, "--verbose-tokenize")) { + builder.verbose_tokenize = true; + } else if (mem.eql(u8, arg, "--verbose-ast")) { + builder.verbose_ast = true; + } else if (mem.eql(u8, arg, "--verbose-link")) { + builder.verbose_link = true; + } else if (mem.eql(u8, arg, "--verbose-ir")) { + builder.verbose_ir = true; + } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) { + builder.verbose_llvm_ir = true; + } else if (mem.eql(u8, arg, "--verbose-cimport")) { + builder.verbose_cimport = true; } else { %%io.stderr.printf("Unrecognized argument: {}\n\n", arg); return usage(&builder, false, &io.stderr); @@ -116,27 +128,40 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream) \\ \\General Options: \\ --help Print this help and exit - \\ --build-file [file] Override path to build.zig - \\ --cache-dir [path] Override path to cache directory \\ --verbose Print commands before executing them - \\ --debug-build-verbose Print verbose debugging information for the build system itself - \\ --prefix [prefix] Override default install prefix + \\ --prefix $path Override default install prefix \\ \\Project-Specific Options: \\ ); if (builder.available_options_list.len == 0) { - %%out_stream.printf(" (none)\n"); + %%out_stream.print(" (none)\n"); } else { for (builder.available_options_list.toSliceConst()) |option| { const name = %%fmt.allocPrint(allocator, - " -D{}=({})", option.name, Builder.typeIdName(option.type_id)); + " -D{}=${}", option.name, Builder.typeIdName(option.type_id)); defer allocator.free(name); - %%out_stream.printf("{s24} {}\n", name, option.description); + %%out_stream.print("{s24} {}\n", name, option.description); } } + %%out_stream.write( + \\ + \\Advanced Options: + \\ --build-file $file Override path to build.zig + \\ --cache-dir $path Override path to zig cache directory + \\ --verbose-tokenize Enable compiler debug output for tokenization + \\ --verbose-ast Enable compiler debug output for parsing into an AST + \\ --verbose-link Enable compiler debug output for linking + \\ --verbose-ir Enable compiler debug output for Zig IR + \\ --verbose-llvm-ir Enable compiler debug output for LLVM IR + \\ --verbose-cimport Enable compiler debug output for C imports + \\ + ); + + %%out_stream.flush(); + if (out_stream == &io.stderr) return error.InvalidArgs; } diff --git a/std/special/compiler_rt/comparetf2.zig b/std/special/compiler_rt/comparetf2.zig index 45c7cb5037..f1552ca61f 100644 --- a/std/special/compiler_rt/comparetf2.zig +++ b/std/special/compiler_rt/comparetf2.zig @@ -20,7 +20,7 @@ const infRep = exponentMask; const builtin = @import("builtin"); const is_test = builtin.is_test; -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __letf2(a: f128, b: f128) -> c_int { @setDebugSafety(this, is_test); diff --git a/std/special/compiler_rt/fixunsdfdi.zig b/std/special/compiler_rt/fixunsdfdi.zig index 0290ad3975..5f730bbc85 100644 --- a/std/special/compiler_rt/fixunsdfdi.zig +++ b/std/special/compiler_rt/fixunsdfdi.zig @@ -1,6 +1,6 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __fixunsdfdi(a: f64) -> u64 { @setDebugSafety(this, builtin.is_test); diff --git a/std/special/compiler_rt/fixunsdfsi.zig b/std/special/compiler_rt/fixunsdfsi.zig index 1dbc2525f2..784d5fde4f 100644 --- a/std/special/compiler_rt/fixunsdfsi.zig +++ b/std/special/compiler_rt/fixunsdfsi.zig @@ -1,6 +1,6 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __fixunsdfsi(a: f64) -> u32 { @setDebugSafety(this, builtin.is_test); diff --git a/std/special/compiler_rt/fixunsdfti.zig b/std/special/compiler_rt/fixunsdfti.zig index 33b0e7c274..579455c2f9 100644 --- a/std/special/compiler_rt/fixunsdfti.zig +++ b/std/special/compiler_rt/fixunsdfti.zig @@ -1,6 +1,6 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __fixunsdfti(a: f64) -> u128 { @setDebugSafety(this, builtin.is_test); diff --git a/std/special/compiler_rt/fixunssfdi.zig b/std/special/compiler_rt/fixunssfdi.zig index c183f17c62..eab553d8c9 100644 --- a/std/special/compiler_rt/fixunssfdi.zig +++ b/std/special/compiler_rt/fixunssfdi.zig @@ -1,6 +1,6 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __fixunssfdi(a: f32) -> u64 { @setDebugSafety(this, builtin.is_test); diff --git a/std/special/compiler_rt/fixunssfsi.zig b/std/special/compiler_rt/fixunssfsi.zig index 51ceef65d3..18c0e66677 100644 --- a/std/special/compiler_rt/fixunssfsi.zig +++ b/std/special/compiler_rt/fixunssfsi.zig @@ -1,6 +1,6 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __fixunssfsi(a: f32) -> u32 { @setDebugSafety(this, builtin.is_test); diff --git a/std/special/compiler_rt/fixunssfti.zig b/std/special/compiler_rt/fixunssfti.zig index 69e1c82a9d..f513604247 100644 --- a/std/special/compiler_rt/fixunssfti.zig +++ b/std/special/compiler_rt/fixunssfti.zig @@ -1,6 +1,6 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __fixunssfti(a: f32) -> u128 { @setDebugSafety(this, builtin.is_test); diff --git a/std/special/compiler_rt/fixunstfdi.zig b/std/special/compiler_rt/fixunstfdi.zig index a5dbe0f52e..85212e2176 100644 --- a/std/special/compiler_rt/fixunstfdi.zig +++ b/std/special/compiler_rt/fixunstfdi.zig @@ -1,6 +1,6 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __fixunstfdi(a: f128) -> u64 { @setDebugSafety(this, builtin.is_test); diff --git a/std/special/compiler_rt/fixunstfsi.zig b/std/special/compiler_rt/fixunstfsi.zig index d488f4c602..33c85c9224 100644 --- a/std/special/compiler_rt/fixunstfsi.zig +++ b/std/special/compiler_rt/fixunstfsi.zig @@ -1,6 +1,6 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __fixunstfsi(a: f128) -> u32 { @setDebugSafety(this, builtin.is_test); diff --git a/std/special/compiler_rt/fixunstfti.zig b/std/special/compiler_rt/fixunstfti.zig index fc5c645d72..1bf7fbab4b 100644 --- a/std/special/compiler_rt/fixunstfti.zig +++ b/std/special/compiler_rt/fixunstfti.zig @@ -1,6 +1,6 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __fixunstfti(a: f128) -> u128 { @setDebugSafety(this, builtin.is_test); diff --git a/std/special/compiler_rt/index.zig b/std/special/compiler_rt/index.zig index 4a4d71fde9..bea06a0b41 100644 --- a/std/special/compiler_rt/index.zig +++ b/std/special/compiler_rt/index.zig @@ -26,7 +26,7 @@ const win32 = builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch. const win64 = builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.x86_64; const win32_nocrt = win32 and !builtin.link_libc; const win64_nocrt = win64 and !builtin.link_libc; -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +pub const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak; const strong_linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong; const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4; @@ -152,10 +152,6 @@ export nakedcc fn _chkstk() align(4) { @setGlobalLinkage(_chkstk, builtin.GlobalLinkage.Internal); } -// TODO The implementation from compiler-rt causes crashes and -// the implementation from disassembled ntdll seems to depend on -// thread local storage. So we have given up this safety check -// and simply have `ret`. export nakedcc fn __chkstk() align(4) { @setDebugSafety(this, false); diff --git a/std/special/compiler_rt/udivmoddi4.zig b/std/special/compiler_rt/udivmoddi4.zig index 2e167bc64a..8005538d9a 100644 --- a/std/special/compiler_rt/udivmoddi4.zig +++ b/std/special/compiler_rt/udivmoddi4.zig @@ -1,6 +1,6 @@ const udivmod = @import("udivmod.zig").udivmod; const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __udivmoddi4(a: u64, b: u64, maybe_rem: ?&u64) -> u64 { @setDebugSafety(this, builtin.is_test); diff --git a/std/special/compiler_rt/udivmodti4.zig b/std/special/compiler_rt/udivmodti4.zig index d7507e9521..2ee2fdb57f 100644 --- a/std/special/compiler_rt/udivmodti4.zig +++ b/std/special/compiler_rt/udivmodti4.zig @@ -1,6 +1,6 @@ const udivmod = @import("udivmod.zig").udivmod; const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __udivmodti4(a: u128, b: u128, maybe_rem: ?&u128) -> u128 { @setDebugSafety(this, builtin.is_test); diff --git a/std/special/compiler_rt/udivti3.zig b/std/special/compiler_rt/udivti3.zig index 67ea15eb96..3764449758 100644 --- a/std/special/compiler_rt/udivti3.zig +++ b/std/special/compiler_rt/udivti3.zig @@ -1,6 +1,6 @@ const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4; const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __udivti3(a: u128, b: u128) -> u128 { @setDebugSafety(this, builtin.is_test); diff --git a/std/special/compiler_rt/umodti3.zig b/std/special/compiler_rt/umodti3.zig index e4a4e7a7ee..0ad9e127b3 100644 --- a/std/special/compiler_rt/umodti3.zig +++ b/std/special/compiler_rt/umodti3.zig @@ -1,6 +1,6 @@ const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4; const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.LinkOnce; +const linkage = @import("index.zig").linkage; export fn __umodti3(a: u128, b: u128) -> u128 { @setDebugSafety(this, builtin.is_test); diff --git a/test/behavior.zig b/test/behavior.zig index 54c954be3d..952c725e8c 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -40,6 +40,7 @@ comptime { _ = @import("cases/this.zig"); _ = @import("cases/try.zig"); _ = @import("cases/undefined.zig"); + _ = @import("cases/union.zig"); _ = @import("cases/var_args.zig"); _ = @import("cases/void.zig"); _ = @import("cases/while.zig"); diff --git a/test/cases/align.zig b/test/cases/align.zig index cd806a5dc6..3bf0d9c9af 100644 --- a/test/cases/align.zig +++ b/test/cases/align.zig @@ -188,6 +188,6 @@ test "alignstack" { } fn fnWithAlignedStack() -> i32 { - @setAlignStack(1024); + @setAlignStack(256); return 1234; } diff --git a/test/cases/union.zig b/test/cases/union.zig new file mode 100644 index 0000000000..4b8ccb7245 --- /dev/null +++ b/test/cases/union.zig @@ -0,0 +1,33 @@ +const assert = @import("std").debug.assert; + +const Value = enum { + Int: u64, + Array: [9]u8, +}; + +const Agg = struct { + val1: Value, + val2: Value, +}; + +const v1 = Value.Int { 1234 }; +const v2 = Value.Array { []u8{3} ** 9 }; + +const err = (%Agg)(Agg { + .val1 = v1, + .val2 = v2, +}); + +const array = []Value { v1, v2, v1, v2}; + + +test "unions embedded in aggregate types" { + switch (array[1]) { + Value.Array => |arr| assert(arr[4] == 3), + else => unreachable, + } + switch((%%err).val1) { + Value.Int => |x| assert(x == 1234), + else => unreachable, + } +} diff --git a/test/compile_errors.zig b/test/compile_errors.zig index dd25886d2b..f8e08d599f 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2187,6 +2187,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:3:5: error: alignstack set twice", ".tmp_source.zig:2:5: note: first set here"); + cases.add("@setAlignStack too big", + \\export fn entry() { + \\ @setAlignStack(511 + 1); + \\} + , + ".tmp_source.zig:2:5: error: attempt to @setAlignStack(512); maximum is 256"); + cases.add("storing runtime value in compile time variable then using it", \\const Mode = @import("builtin").Mode; \\ @@ -2231,4 +2238,41 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\} , ".tmp_source.zig:37:16: error: cannot store runtime value in compile time variable"); + + cases.add("field access of opaque type", + \\const MyType = @OpaqueType(); + \\ + \\export fn entry() -> bool { + \\ var x: i32 = 1; + \\ return bar(@ptrCast(&MyType, &x)); + \\} + \\ + \\fn bar(x: &MyType) -> bool { + \\ return x.blah; + \\} + , + ".tmp_source.zig:9:13: error: type '&MyType' does not support field access"); + + cases.add("carriage return special case", + "fn test() -> bool {\r\n" ++ + " true\r\n" ++ + "}\r\n" + , + ".tmp_source.zig:1:20: error: invalid carriage return, only '\\n' line endings are supported"); + + cases.add("non-printable invalid character", + "\xff\xfe" ++ + \\fn test() -> bool {\r + \\ true\r + \\} + , + ".tmp_source.zig:1:1: error: invalid character: '\\xff'"); + + cases.add("non-printable invalid character with escape alternative", + "fn test() -> bool {\n" ++ + "\ttrue\n" ++ + "}\n" + , + ".tmp_source.zig:2:1: error: invalid character: '\\t'"); + } |
