| author | |
| committer | |
| log | d62f7c6b605a672f032aff8870496d2ae2366017 |
| tree | 659ae46ac0061fcafd3ec29de8682ec1f18e97cc |
| parent | e7912dee9bd63b03415f441b4de9b3babc79c859 |
| parent | 8b1900e5df76a126404c6905b9e91136c738da55 |
21 files changed, 1020 insertions(+), 205 deletions(-)
doc/langref.html.in+16| ... | ... | @@ -8114,7 +8114,23 @@ pub const TypeInfo = union(TypeId) { |
| 8114 | 8114 | This function returns a compile-time constant, which is the type of the |
| 8115 | 8115 | expression passed as an argument. The expression is evaluated. |
| 8116 | 8116 | </p> |
| 8117 | <p>{#syntax#}@typeOf{#endsyntax#} guarantees no run-time side-effects within the expression:</p> | |
| 8118 | {#code_begin|test#} | |
| 8119 | const std = @import("std"); | |
| 8120 | const assert = std.debug.assert; | |
| 8121 | ||
| 8122 | test "no runtime side effects" { | |
| 8123 | var data: i32 = 0; | |
| 8124 | const T = @typeOf(foo(i32, &data)); | |
| 8125 | comptime assert(T == i32); | |
| 8126 | assert(data == 0); | |
| 8127 | } | |
| 8117 | 8128 | |
| 8129 | fn foo(comptime T: type, ptr: *T) T { | |
| 8130 | ptr.* += 1; | |
| 8131 | return ptr.*; | |
| 8132 | } | |
| 8133 | {#code_end#} | |
| 8118 | 8134 | {#header_close#} |
| 8119 | 8135 | |
| 8120 | 8136 | {#header_open|@unionInit#} |
src/all_types.hpp+11-1| ... | ... | @@ -627,7 +627,7 @@ struct AstNodeParamDecl { |
| 627 | 627 | AstNode *type; |
| 628 | 628 | Token *var_token; |
| 629 | 629 | bool is_noalias; |
| 630 | bool is_inline; | |
| 630 | bool is_comptime; | |
| 631 | 631 | bool is_var_args; |
| 632 | 632 | }; |
| 633 | 633 | |
| ... | ... | @@ -2104,6 +2104,7 @@ enum ScopeId { |
| 2104 | 2104 | ScopeIdFnDef, |
| 2105 | 2105 | ScopeIdCompTime, |
| 2106 | 2106 | ScopeIdRuntime, |
| 2107 | ScopeIdTypeOf, | |
| 2107 | 2108 | }; |
| 2108 | 2109 | |
| 2109 | 2110 | struct Scope { |
| ... | ... | @@ -2244,6 +2245,13 @@ struct ScopeFnDef { |
| 2244 | 2245 | ZigFn *fn_entry; |
| 2245 | 2246 | }; |
| 2246 | 2247 | |
| 2248 | // This scope is created for a @typeOf. | |
| 2249 | // All runtime side-effects are elided within it. | |
| 2250 | // NodeTypeFnCallExpr | |
| 2251 | struct ScopeTypeOf { | |
| 2252 | Scope base; | |
| 2253 | }; | |
| 2254 | ||
| 2247 | 2255 | // synchronized with code in define_builtin_compile_vars |
| 2248 | 2256 | enum AtomicOrder { |
| 2249 | 2257 | AtomicOrderUnordered, |
| ... | ... | @@ -2711,6 +2719,7 @@ struct IrInstructionCallSrc { |
| 2711 | 2719 | IrInstruction *new_stack; |
| 2712 | 2720 | FnInline fn_inline; |
| 2713 | 2721 | bool is_async; |
| 2722 | bool is_async_call_builtin; | |
| 2714 | 2723 | bool is_comptime; |
| 2715 | 2724 | }; |
| 2716 | 2725 | |
| ... | ... | @@ -2727,6 +2736,7 @@ struct IrInstructionCallGen { |
| 2727 | 2736 | IrInstruction *new_stack; |
| 2728 | 2737 | FnInline fn_inline; |
| 2729 | 2738 | bool is_async; |
| 2739 | bool is_async_call_builtin; | |
| 2730 | 2740 | }; |
| 2731 | 2741 | |
| 2732 | 2742 | struct IrInstructionConst { |
src/analyze.cpp+33-4| ... | ... | @@ -197,6 +197,12 @@ Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent) { |
| 197 | 197 | return &scope->base; |
| 198 | 198 | } |
| 199 | 199 | |
| 200 | Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent) { | |
| 201 | ScopeTypeOf *scope = allocate<ScopeTypeOf>(1); | |
| 202 | init_scope(g, &scope->base, ScopeIdTypeOf, node, parent); | |
| 203 | return &scope->base; | |
| 204 | } | |
| 205 | ||
| 200 | 206 | ZigType *get_scope_import(Scope *scope) { |
| 201 | 207 | while (scope) { |
| 202 | 208 | if (scope->id == ScopeIdDecls) { |
| ... | ... | @@ -209,6 +215,22 @@ ZigType *get_scope_import(Scope *scope) { |
| 209 | 215 | zig_unreachable(); |
| 210 | 216 | } |
| 211 | 217 | |
| 218 | ScopeTypeOf *get_scope_typeof(Scope *scope) { | |
| 219 | while (scope) { | |
| 220 | switch (scope->id) { | |
| 221 | case ScopeIdTypeOf: | |
| 222 | return reinterpret_cast<ScopeTypeOf *>(scope); | |
| 223 | case ScopeIdFnDef: | |
| 224 | case ScopeIdDecls: | |
| 225 | return nullptr; | |
| 226 | default: | |
| 227 | scope = scope->parent; | |
| 228 | continue; | |
| 229 | } | |
| 230 | } | |
| 231 | zig_unreachable(); | |
| 232 | } | |
| 233 | ||
| 212 | 234 | static ZigType *new_container_type_entry(CodeGen *g, ZigTypeId id, AstNode *source_node, Scope *parent_scope, |
| 213 | 235 | Buf *bare_name) |
| 214 | 236 | { |
| ... | ... | @@ -1556,7 +1578,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc |
| 1556 | 1578 | AstNode *param_node = fn_proto->params.at(fn_type_id.next_param_index); |
| 1557 | 1579 | assert(param_node->type == NodeTypeParamDecl); |
| 1558 | 1580 | |
| 1559 | bool param_is_comptime = param_node->data.param_decl.is_inline; | |
| 1581 | bool param_is_comptime = param_node->data.param_decl.is_comptime; | |
| 1560 | 1582 | bool param_is_var_args = param_node->data.param_decl.is_var_args; |
| 1561 | 1583 | |
| 1562 | 1584 | if (param_is_comptime) { |
| ... | ... | @@ -4393,7 +4415,7 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) { |
| 4393 | 4415 | |
| 4394 | 4416 | if (g->verbose_ir) { |
| 4395 | 4417 | fprintf(stderr, "fn %s() { // (analyzed)\n", buf_ptr(&fn->symbol_name)); |
| 4396 | ir_print(g, stderr, &fn->analyzed_executable, 4); | |
| 4418 | ir_print(g, stderr, &fn->analyzed_executable, 4, 2); | |
| 4397 | 4419 | fprintf(stderr, "}\n"); |
| 4398 | 4420 | } |
| 4399 | 4421 | fn->anal_state = FnAnalStateComplete; |
| ... | ... | @@ -4427,7 +4449,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) { |
| 4427 | 4449 | fprintf(stderr, "\n"); |
| 4428 | 4450 | ast_render(stderr, fn_table_entry->body_node, 4); |
| 4429 | 4451 | fprintf(stderr, "\n{ // (IR)\n"); |
| 4430 | ir_print(g, stderr, &fn_table_entry->ir_executable, 4); | |
| 4452 | ir_print(g, stderr, &fn_table_entry->ir_executable, 4, 1); | |
| 4431 | 4453 | fprintf(stderr, "}\n"); |
| 4432 | 4454 | } |
| 4433 | 4455 | |
| ... | ... | @@ -5705,6 +5727,10 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { |
| 5705 | 5727 | |
| 5706 | 5728 | for (size_t i = 0; i < fn->call_list.length; i += 1) { |
| 5707 | 5729 | IrInstructionCallGen *call = fn->call_list.at(i); |
| 5730 | if (call->new_stack != nullptr) { | |
| 5731 | // don't need to allocate a frame for this | |
| 5732 | continue; | |
| 5733 | } | |
| 5708 | 5734 | ZigFn *callee = call->fn_entry; |
| 5709 | 5735 | if (callee == nullptr) { |
| 5710 | 5736 | add_node_error(g, call->base.source_node, |
| ... | ... | @@ -8234,6 +8260,10 @@ static void resolve_llvm_types_anyerror(CodeGen *g) { |
| 8234 | 8260 | } |
| 8235 | 8261 | |
| 8236 | 8262 | static void resolve_llvm_types_async_frame(CodeGen *g, ZigType *frame_type, ResolveStatus wanted_resolve_status) { |
| 8263 | Error err; | |
| 8264 | if ((err = type_resolve(g, frame_type, ResolveStatusSizeKnown))) | |
| 8265 | zig_unreachable(); | |
| 8266 | ||
| 8237 | 8267 | ZigType *passed_frame_type = fn_is_async(frame_type->data.frame.fn) ? frame_type : nullptr; |
| 8238 | 8268 | resolve_llvm_types_struct(g, frame_type->data.frame.locals_struct, wanted_resolve_status, passed_frame_type); |
| 8239 | 8269 | frame_type->llvm_type = frame_type->data.frame.locals_struct->llvm_type; |
| ... | ... | @@ -8375,7 +8405,6 @@ static void resolve_llvm_types_any_frame(CodeGen *g, ZigType *any_frame_type, Re |
| 8375 | 8405 | } |
| 8376 | 8406 | |
| 8377 | 8407 | static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) { |
| 8378 | assert(type->id == ZigTypeIdOpaque || type_is_resolved(type, ResolveStatusSizeKnown)); | |
| 8379 | 8408 | assert(wanted_resolve_status > ResolveStatusSizeKnown); |
| 8380 | 8409 | switch (type->id) { |
| 8381 | 8410 | case ZigTypeIdInvalid: |
src/analyze.hpp+2| ... | ... | @@ -85,6 +85,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node); |
| 85 | 85 | ZigFn *scope_fn_entry(Scope *scope); |
| 86 | 86 | ZigPackage *scope_package(Scope *scope); |
| 87 | 87 | ZigType *get_scope_import(Scope *scope); |
| 88 | ScopeTypeOf *get_scope_typeof(Scope *scope); | |
| 88 | 89 | void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, Scope *parent_scope); |
| 89 | 90 | ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name, |
| 90 | 91 | bool is_const, ConstExprValue *init_value, Tld *src_tld, ZigType *var_type); |
| ... | ... | @@ -112,6 +113,7 @@ ScopeSuspend *create_suspend_scope(CodeGen *g, AstNode *node, Scope *parent); |
| 112 | 113 | ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn *fn_entry); |
| 113 | 114 | Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent); |
| 114 | 115 | Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruction *is_comptime); |
| 116 | Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent); | |
| 115 | 117 | |
| 116 | 118 | void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str); |
| 117 | 119 | ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str); |
src/ast_render.cpp+1-1| ... | ... | @@ -448,7 +448,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 448 | 448 | assert(param_decl->type == NodeTypeParamDecl); |
| 449 | 449 | if (param_decl->data.param_decl.name != nullptr) { |
| 450 | 450 | const char *noalias_str = param_decl->data.param_decl.is_noalias ? "noalias " : ""; |
| 451 | const char *inline_str = param_decl->data.param_decl.is_inline ? "inline " : ""; | |
| 451 | const char *inline_str = param_decl->data.param_decl.is_comptime ? "comptime " : ""; | |
| 452 | 452 | fprintf(ar->f, "%s%s", noalias_str, inline_str); |
| 453 | 453 | print_symbol(ar, param_decl->data.param_decl.name); |
| 454 | 454 | fprintf(ar->f, ": "); |
src/codegen.cpp+54-21| ... | ... | @@ -645,6 +645,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { |
| 645 | 645 | case ScopeIdSuspend: |
| 646 | 646 | case ScopeIdCompTime: |
| 647 | 647 | case ScopeIdRuntime: |
| 648 | case ScopeIdTypeOf: | |
| 648 | 649 | return get_di_scope(g, scope->parent); |
| 649 | 650 | } |
| 650 | 651 | zig_unreachable(); |
| ... | ... | @@ -3757,6 +3758,7 @@ static void render_async_var_decls(CodeGen *g, Scope *scope) { |
| 3757 | 3758 | case ScopeIdSuspend: |
| 3758 | 3759 | case ScopeIdCompTime: |
| 3759 | 3760 | case ScopeIdRuntime: |
| 3761 | case ScopeIdTypeOf: | |
| 3760 | 3762 | scope = scope->parent; |
| 3761 | 3763 | continue; |
| 3762 | 3764 | } |
| ... | ... | @@ -3824,17 +3826,18 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3824 | 3826 | LLVMValueRef awaiter_init_val; |
| 3825 | 3827 | LLVMValueRef ret_ptr; |
| 3826 | 3828 | if (callee_is_async) { |
| 3827 | if (instruction->is_async) { | |
| 3828 | if (instruction->new_stack == nullptr) { | |
| 3829 | awaiter_init_val = zero; | |
| 3829 | if (instruction->new_stack == nullptr) { | |
| 3830 | if (instruction->is_async) { | |
| 3830 | 3831 | frame_result_loc = result_loc; |
| 3831 | ||
| 3832 | if (ret_has_bits) { | |
| 3833 | // Use the result location which is inside the frame if this is an async call. | |
| 3834 | ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, ""); | |
| 3835 | } | |
| 3836 | } else if (cc == CallingConventionAsync) { | |
| 3837 | awaiter_init_val = zero; | |
| 3832 | } else { | |
| 3833 | frame_result_loc = ir_llvm_value(g, instruction->frame_result_loc); | |
| 3834 | } | |
| 3835 | } else { | |
| 3836 | if (instruction->new_stack->value.type->id == ZigTypeIdPointer && | |
| 3837 | instruction->new_stack->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame) | |
| 3838 | { | |
| 3839 | frame_result_loc = ir_llvm_value(g, instruction->new_stack); | |
| 3840 | } else { | |
| 3838 | 3841 | LLVMValueRef frame_slice_ptr = ir_llvm_value(g, instruction->new_stack); |
| 3839 | 3842 | if (ir_want_runtime_safety(g, &instruction->base)) { |
| 3840 | 3843 | LLVMValueRef given_len_ptr = LLVMBuildStructGEP(g->builder, frame_slice_ptr, slice_len_index, ""); |
| ... | ... | @@ -3854,15 +3857,37 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3854 | 3857 | } |
| 3855 | 3858 | LLVMValueRef frame_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_slice_ptr, slice_ptr_index, ""); |
| 3856 | 3859 | LLVMValueRef frame_ptr = LLVMBuildLoad(g->builder, frame_ptr_ptr, ""); |
| 3857 | frame_result_loc = LLVMBuildBitCast(g->builder, frame_ptr, | |
| 3858 | get_llvm_type(g, instruction->base.value.type), ""); | |
| 3860 | if (instruction->fn_entry == nullptr) { | |
| 3861 | ZigType *anyframe_type = get_any_frame_type(g, src_return_type); | |
| 3862 | frame_result_loc = LLVMBuildBitCast(g->builder, frame_ptr, get_llvm_type(g, anyframe_type), ""); | |
| 3863 | } else { | |
| 3864 | ZigType *ptr_frame_type = get_pointer_to_type(g, | |
| 3865 | get_fn_frame_type(g, instruction->fn_entry), false); | |
| 3866 | frame_result_loc = LLVMBuildBitCast(g->builder, frame_ptr, | |
| 3867 | get_llvm_type(g, ptr_frame_type), ""); | |
| 3868 | } | |
| 3869 | } | |
| 3870 | } | |
| 3871 | if (instruction->is_async) { | |
| 3872 | if (instruction->new_stack == nullptr) { | |
| 3873 | awaiter_init_val = zero; | |
| 3859 | 3874 | |
| 3860 | 3875 | if (ret_has_bits) { |
| 3861 | // Use the result location provided to the @asyncCall builtin | |
| 3862 | ret_ptr = result_loc; | |
| 3876 | // Use the result location which is inside the frame if this is an async call. | |
| 3877 | ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, ""); | |
| 3863 | 3878 | } |
| 3864 | 3879 | } else { |
| 3865 | zig_unreachable(); | |
| 3880 | awaiter_init_val = zero; | |
| 3881 | ||
| 3882 | if (ret_has_bits) { | |
| 3883 | if (result_loc != nullptr) { | |
| 3884 | // Use the result location provided to the @asyncCall builtin | |
| 3885 | ret_ptr = result_loc; | |
| 3886 | } else { | |
| 3887 | // no result location provided to @asyncCall - use the one inside the frame. | |
| 3888 | ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, ""); | |
| 3889 | } | |
| 3890 | } | |
| 3866 | 3891 | } |
| 3867 | 3892 | |
| 3868 | 3893 | // even if prefix_arg_err_ret_stack is true, let the async function do its own |
| ... | ... | @@ -3870,7 +3895,6 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3870 | 3895 | } else { |
| 3871 | 3896 | // async function called as a normal function |
| 3872 | 3897 | |
| 3873 | frame_result_loc = ir_llvm_value(g, instruction->frame_result_loc); | |
| 3874 | 3898 | awaiter_init_val = LLVMBuildPtrToInt(g->builder, g->cur_frame_ptr, usize_type_ref, ""); // caller's own frame pointer |
| 3875 | 3899 | if (ret_has_bits) { |
| 3876 | 3900 | if (result_loc == nullptr) { |
| ... | ... | @@ -3986,7 +4010,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3986 | 4010 | uint32_t arg_start_i = frame_index_arg(g, fn_type->data.fn.fn_type_id.return_type); |
| 3987 | 4011 | |
| 3988 | 4012 | LLVMValueRef casted_frame; |
| 3989 | if (instruction->new_stack != nullptr) { | |
| 4013 | if (instruction->new_stack != nullptr && instruction->fn_entry == nullptr) { | |
| 3990 | 4014 | // We need the frame type to be a pointer to a struct that includes the args |
| 3991 | 4015 | size_t field_count = arg_start_i + gen_param_values.length; |
| 3992 | 4016 | LLVMTypeRef *field_types = allocate_nonzero<LLVMTypeRef>(field_count); |
| ... | ... | @@ -4012,7 +4036,8 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 4012 | 4036 | if (instruction->is_async) { |
| 4013 | 4037 | gen_resume(g, fn_val, frame_result_loc, ResumeIdCall); |
| 4014 | 4038 | if (instruction->new_stack != nullptr) { |
| 4015 | return frame_result_loc; | |
| 4039 | return LLVMBuildBitCast(g->builder, frame_result_loc, | |
| 4040 | get_llvm_type(g, instruction->base.value.type), ""); | |
| 4016 | 4041 | } |
| 4017 | 4042 | return nullptr; |
| 4018 | 4043 | } else { |
| ... | ... | @@ -4039,7 +4064,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 4039 | 4064 | } |
| 4040 | 4065 | } |
| 4041 | 4066 | |
| 4042 | if (instruction->new_stack == nullptr) { | |
| 4067 | if (instruction->new_stack == nullptr || instruction->is_async_call_builtin) { | |
| 4043 | 4068 | result = ZigLLVMBuildCall(g->builder, fn_val, |
| 4044 | 4069 | gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, ""); |
| 4045 | 4070 | } else if (instruction->is_async) { |
| ... | ... | @@ -5942,12 +5967,17 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) { |
| 5942 | 5967 | |
| 5943 | 5968 | for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) { |
| 5944 | 5969 | IrBasicBlock *current_block = executable->basic_block_list.at(block_i); |
| 5970 | if (get_scope_typeof(current_block->scope) != nullptr) { | |
| 5971 | LLVMBuildBr(g->builder, current_block->llvm_block); | |
| 5972 | } | |
| 5945 | 5973 | assert(current_block->llvm_block); |
| 5946 | 5974 | LLVMPositionBuilderAtEnd(g->builder, current_block->llvm_block); |
| 5947 | 5975 | for (size_t instr_i = 0; instr_i < current_block->instruction_list.length; instr_i += 1) { |
| 5948 | 5976 | IrInstruction *instruction = current_block->instruction_list.at(instr_i); |
| 5949 | 5977 | if (instruction->ref_count == 0 && !ir_has_side_effects(instruction)) |
| 5950 | 5978 | continue; |
| 5979 | if (get_scope_typeof(instruction->scope) != nullptr) | |
| 5980 | continue; | |
| 5951 | 5981 | |
| 5952 | 5982 | if (!g->strip_debug_symbols) { |
| 5953 | 5983 | set_debug_location(g, instruction); |
| ... | ... | @@ -6340,9 +6370,12 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c |
| 6340 | 6370 | ZigType *type_entry = const_val->type; |
| 6341 | 6371 | assert(type_has_bits(type_entry)); |
| 6342 | 6372 | |
| 6343 | switch (const_val->special) { | |
| 6373 | check: switch (const_val->special) { | |
| 6344 | 6374 | case ConstValSpecialLazy: |
| 6345 | zig_unreachable(); | |
| 6375 | if ((err = ir_resolve_lazy(g, nullptr, const_val))) { | |
| 6376 | report_errors_and_exit(g); | |
| 6377 | } | |
| 6378 | goto check; | |
| 6346 | 6379 | case ConstValSpecialRuntime: |
| 6347 | 6380 | zig_unreachable(); |
| 6348 | 6381 | case ConstValSpecialUndef: |
src/ir.cpp+239-116| ... | ... | @@ -1382,7 +1382,7 @@ static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, Ast |
| 1382 | 1382 | |
| 1383 | 1383 | static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 1384 | 1384 | ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, |
| 1385 | bool is_comptime, FnInline fn_inline, bool is_async, | |
| 1385 | bool is_comptime, FnInline fn_inline, bool is_async, bool is_async_call_builtin, | |
| 1386 | 1386 | IrInstruction *new_stack, ResultLoc *result_loc) |
| 1387 | 1387 | { |
| 1388 | 1388 | IrInstructionCallSrc *call_instruction = ir_build_instruction<IrInstructionCallSrc>(irb, scope, source_node); |
| ... | ... | @@ -1393,6 +1393,7 @@ static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *s |
| 1393 | 1393 | call_instruction->args = args; |
| 1394 | 1394 | call_instruction->arg_count = arg_count; |
| 1395 | 1395 | call_instruction->is_async = is_async; |
| 1396 | call_instruction->is_async_call_builtin = is_async_call_builtin; | |
| 1396 | 1397 | call_instruction->new_stack = new_stack; |
| 1397 | 1398 | call_instruction->result_loc = result_loc; |
| 1398 | 1399 | |
| ... | ... | @@ -1410,7 +1411,7 @@ static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *s |
| 1410 | 1411 | |
| 1411 | 1412 | static IrInstructionCallGen *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_instruction, |
| 1412 | 1413 | ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, |
| 1413 | FnInline fn_inline, bool is_async, IrInstruction *new_stack, | |
| 1414 | FnInline fn_inline, bool is_async, IrInstruction *new_stack, bool is_async_call_builtin, | |
| 1414 | 1415 | IrInstruction *result_loc, ZigType *return_type) |
| 1415 | 1416 | { |
| 1416 | 1417 | IrInstructionCallGen *call_instruction = ir_build_instruction<IrInstructionCallGen>(&ira->new_irb, |
| ... | ... | @@ -1422,6 +1423,7 @@ static IrInstructionCallGen *ir_build_call_gen(IrAnalyze *ira, IrInstruction *so |
| 1422 | 1423 | call_instruction->args = args; |
| 1423 | 1424 | call_instruction->arg_count = arg_count; |
| 1424 | 1425 | call_instruction->is_async = is_async; |
| 1426 | call_instruction->is_async_call_builtin = is_async_call_builtin; | |
| 1425 | 1427 | call_instruction->new_stack = new_stack; |
| 1426 | 1428 | call_instruction->result_loc = result_loc; |
| 1427 | 1429 | |
| ... | ... | @@ -3344,6 +3346,7 @@ static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_sco |
| 3344 | 3346 | case ScopeIdSuspend: |
| 3345 | 3347 | case ScopeIdCompTime: |
| 3346 | 3348 | case ScopeIdRuntime: |
| 3349 | case ScopeIdTypeOf: | |
| 3347 | 3350 | scope = scope->parent; |
| 3348 | 3351 | continue; |
| 3349 | 3352 | case ScopeIdDeferExpr: |
| ... | ... | @@ -3399,6 +3402,7 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o |
| 3399 | 3402 | case ScopeIdSuspend: |
| 3400 | 3403 | case ScopeIdCompTime: |
| 3401 | 3404 | case ScopeIdRuntime: |
| 3405 | case ScopeIdTypeOf: | |
| 3402 | 3406 | scope = scope->parent; |
| 3403 | 3407 | continue; |
| 3404 | 3408 | case ScopeIdDeferExpr: |
| ... | ... | @@ -4349,6 +4353,54 @@ static IrInstruction *ir_gen_this(IrBuilder *irb, Scope *orig_scope, AstNode *no |
| 4349 | 4353 | zig_unreachable(); |
| 4350 | 4354 | } |
| 4351 | 4355 | |
| 4356 | static IrInstruction *ir_gen_async_call(IrBuilder *irb, Scope *scope, AstNode *await_node, AstNode *call_node, | |
| 4357 | LVal lval, ResultLoc *result_loc) | |
| 4358 | { | |
| 4359 | size_t arg_offset = 3; | |
| 4360 | if (call_node->data.fn_call_expr.params.length < arg_offset) { | |
| 4361 | add_node_error(irb->codegen, call_node, | |
| 4362 | buf_sprintf("expected at least %" ZIG_PRI_usize " arguments, found %" ZIG_PRI_usize, | |
| 4363 | arg_offset, call_node->data.fn_call_expr.params.length)); | |
| 4364 | return irb->codegen->invalid_instruction; | |
| 4365 | } | |
| 4366 | ||
| 4367 | AstNode *bytes_node = call_node->data.fn_call_expr.params.at(0); | |
| 4368 | IrInstruction *bytes = ir_gen_node(irb, bytes_node, scope); | |
| 4369 | if (bytes == irb->codegen->invalid_instruction) | |
| 4370 | return bytes; | |
| 4371 | ||
| 4372 | AstNode *ret_ptr_node = call_node->data.fn_call_expr.params.at(1); | |
| 4373 | IrInstruction *ret_ptr = ir_gen_node(irb, ret_ptr_node, scope); | |
| 4374 | if (ret_ptr == irb->codegen->invalid_instruction) | |
| 4375 | return ret_ptr; | |
| 4376 | ||
| 4377 | AstNode *fn_ref_node = call_node->data.fn_call_expr.params.at(2); | |
| 4378 | IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope); | |
| 4379 | if (fn_ref == irb->codegen->invalid_instruction) | |
| 4380 | return fn_ref; | |
| 4381 | ||
| 4382 | size_t arg_count = call_node->data.fn_call_expr.params.length - arg_offset; | |
| 4383 | ||
| 4384 | // last "arg" is return pointer | |
| 4385 | IrInstruction **args = allocate<IrInstruction*>(arg_count + 1); | |
| 4386 | ||
| 4387 | for (size_t i = 0; i < arg_count; i += 1) { | |
| 4388 | AstNode *arg_node = call_node->data.fn_call_expr.params.at(i + arg_offset); | |
| 4389 | IrInstruction *arg = ir_gen_node(irb, arg_node, scope); | |
| 4390 | if (arg == irb->codegen->invalid_instruction) | |
| 4391 | return arg; | |
| 4392 | args[i] = arg; | |
| 4393 | } | |
| 4394 | ||
| 4395 | args[arg_count] = ret_ptr; | |
| 4396 | ||
| 4397 | bool is_async = await_node == nullptr; | |
| 4398 | bool is_async_call_builtin = true; | |
| 4399 | IrInstruction *call = ir_build_call_src(irb, scope, call_node, nullptr, fn_ref, arg_count, args, false, | |
| 4400 | FnInlineAuto, is_async, is_async_call_builtin, bytes, result_loc); | |
| 4401 | return ir_lval_wrap(irb, scope, call, lval, result_loc); | |
| 4402 | } | |
| 4403 | ||
| 4352 | 4404 | static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, |
| 4353 | 4405 | ResultLoc *result_loc) |
| 4354 | 4406 | { |
| ... | ... | @@ -4358,7 +4410,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4358 | 4410 | Buf *name = fn_ref_expr->data.symbol_expr.symbol; |
| 4359 | 4411 | auto entry = irb->codegen->builtin_fn_table.maybe_get(name); |
| 4360 | 4412 | |
| 4361 | if (!entry) { // new built in not found | |
| 4413 | if (!entry) { | |
| 4362 | 4414 | add_node_error(irb->codegen, node, |
| 4363 | 4415 | buf_sprintf("invalid builtin function: '%s'", buf_ptr(name))); |
| 4364 | 4416 | return irb->codegen->invalid_instruction; |
| ... | ... | @@ -4379,8 +4431,10 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4379 | 4431 | zig_unreachable(); |
| 4380 | 4432 | case BuiltinFnIdTypeof: |
| 4381 | 4433 | { |
| 4434 | Scope *sub_scope = create_typeof_scope(irb->codegen, node, scope); | |
| 4435 | ||
| 4382 | 4436 | AstNode *arg_node = node->data.fn_call_expr.params.at(0); |
| 4383 | IrInstruction *arg = ir_gen_node(irb, arg_node, scope); | |
| 4437 | IrInstruction *arg = ir_gen_node(irb, arg_node, sub_scope); | |
| 4384 | 4438 | if (arg == irb->codegen->invalid_instruction) |
| 4385 | 4439 | return arg; |
| 4386 | 4440 | |
| ... | ... | @@ -5220,7 +5274,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 5220 | 5274 | FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever; |
| 5221 | 5275 | |
| 5222 | 5276 | IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, |
| 5223 | fn_inline, false, nullptr, result_loc); | |
| 5277 | fn_inline, false, false, nullptr, result_loc); | |
| 5224 | 5278 | return ir_lval_wrap(irb, scope, call, lval, result_loc); |
| 5225 | 5279 | } |
| 5226 | 5280 | case BuiltinFnIdNewStackCall: |
| ... | ... | @@ -5253,53 +5307,11 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 5253 | 5307 | } |
| 5254 | 5308 | |
| 5255 | 5309 | IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, |
| 5256 | FnInlineAuto, false, new_stack, result_loc); | |
| 5310 | FnInlineAuto, false, false, new_stack, result_loc); | |
| 5257 | 5311 | return ir_lval_wrap(irb, scope, call, lval, result_loc); |
| 5258 | 5312 | } |
| 5259 | 5313 | case BuiltinFnIdAsyncCall: |
| 5260 | { | |
| 5261 | size_t arg_offset = 3; | |
| 5262 | if (node->data.fn_call_expr.params.length < arg_offset) { | |
| 5263 | add_node_error(irb->codegen, node, | |
| 5264 | buf_sprintf("expected at least %" ZIG_PRI_usize " arguments, found %" ZIG_PRI_usize, | |
| 5265 | arg_offset, node->data.fn_call_expr.params.length)); | |
| 5266 | return irb->codegen->invalid_instruction; | |
| 5267 | } | |
| 5268 | ||
| 5269 | AstNode *bytes_node = node->data.fn_call_expr.params.at(0); | |
| 5270 | IrInstruction *bytes = ir_gen_node(irb, bytes_node, scope); | |
| 5271 | if (bytes == irb->codegen->invalid_instruction) | |
| 5272 | return bytes; | |
| 5273 | ||
| 5274 | AstNode *ret_ptr_node = node->data.fn_call_expr.params.at(1); | |
| 5275 | IrInstruction *ret_ptr = ir_gen_node(irb, ret_ptr_node, scope); | |
| 5276 | if (ret_ptr == irb->codegen->invalid_instruction) | |
| 5277 | return ret_ptr; | |
| 5278 | ||
| 5279 | AstNode *fn_ref_node = node->data.fn_call_expr.params.at(2); | |
| 5280 | IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope); | |
| 5281 | if (fn_ref == irb->codegen->invalid_instruction) | |
| 5282 | return fn_ref; | |
| 5283 | ||
| 5284 | size_t arg_count = node->data.fn_call_expr.params.length - arg_offset; | |
| 5285 | ||
| 5286 | // last "arg" is return pointer | |
| 5287 | IrInstruction **args = allocate<IrInstruction*>(arg_count + 1); | |
| 5288 | ||
| 5289 | for (size_t i = 0; i < arg_count; i += 1) { | |
| 5290 | AstNode *arg_node = node->data.fn_call_expr.params.at(i + arg_offset); | |
| 5291 | IrInstruction *arg = ir_gen_node(irb, arg_node, scope); | |
| 5292 | if (arg == irb->codegen->invalid_instruction) | |
| 5293 | return arg; | |
| 5294 | args[i] = arg; | |
| 5295 | } | |
| 5296 | ||
| 5297 | args[arg_count] = ret_ptr; | |
| 5298 | ||
| 5299 | IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, | |
| 5300 | FnInlineAuto, true, bytes, result_loc); | |
| 5301 | return ir_lval_wrap(irb, scope, call, lval, result_loc); | |
| 5302 | } | |
| 5314 | return ir_gen_async_call(irb, scope, nullptr, node, lval, result_loc); | |
| 5303 | 5315 | case BuiltinFnIdTypeId: |
| 5304 | 5316 | { |
| 5305 | 5317 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); |
| ... | ... | @@ -5603,7 +5615,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node |
| 5603 | 5615 | |
| 5604 | 5616 | bool is_async = node->data.fn_call_expr.is_async; |
| 5605 | 5617 | IrInstruction *fn_call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, |
| 5606 | FnInlineAuto, is_async, nullptr, result_loc); | |
| 5618 | FnInlineAuto, is_async, false, nullptr, result_loc); | |
| 5607 | 5619 | return ir_lval_wrap(irb, scope, fn_call, lval, result_loc); |
| 5608 | 5620 | } |
| 5609 | 5621 | |
| ... | ... | @@ -7896,6 +7908,19 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 7896 | 7908 | { |
| 7897 | 7909 | assert(node->type == NodeTypeAwaitExpr); |
| 7898 | 7910 | |
| 7911 | AstNode *expr_node = node->data.await_expr.expr; | |
| 7912 | if (expr_node->type == NodeTypeFnCallExpr && expr_node->data.fn_call_expr.is_builtin) { | |
| 7913 | AstNode *fn_ref_expr = expr_node->data.fn_call_expr.fn_ref_expr; | |
| 7914 | Buf *name = fn_ref_expr->data.symbol_expr.symbol; | |
| 7915 | auto entry = irb->codegen->builtin_fn_table.maybe_get(name); | |
| 7916 | if (entry != nullptr) { | |
| 7917 | BuiltinFnEntry *builtin_fn = entry->value; | |
| 7918 | if (builtin_fn->id == BuiltinFnIdAsyncCall) { | |
| 7919 | return ir_gen_async_call(irb, scope, node, expr_node, lval, result_loc); | |
| 7920 | } | |
| 7921 | } | |
| 7922 | } | |
| 7923 | ||
| 7899 | 7924 | ZigFn *fn_entry = exec_fn_entry(irb->exec); |
| 7900 | 7925 | if (!fn_entry) { |
| 7901 | 7926 | add_node_error(irb->codegen, node, buf_sprintf("await outside function definition")); |
| ... | ... | @@ -7911,7 +7936,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 7911 | 7936 | return irb->codegen->invalid_instruction; |
| 7912 | 7937 | } |
| 7913 | 7938 | |
| 7914 | IrInstruction *target_inst = ir_gen_node_extra(irb, node->data.await_expr.expr, scope, LValPtr, nullptr); | |
| 7939 | IrInstruction *target_inst = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr); | |
| 7915 | 7940 | if (target_inst == irb->codegen->invalid_instruction) |
| 7916 | 7941 | return irb->codegen->invalid_instruction; |
| 7917 | 7942 | |
| ... | ... | @@ -8269,6 +8294,10 @@ static ConstExprValue *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec |
| 8269 | 8294 | break; |
| 8270 | 8295 | } |
| 8271 | 8296 | } |
| 8297 | if (get_scope_typeof(instruction->scope) != nullptr) { | |
| 8298 | // doesn't count, it's inside a @typeOf() | |
| 8299 | continue; | |
| 8300 | } | |
| 8272 | 8301 | exec_add_error_node(codegen, exec, instruction->source_node, |
| 8273 | 8302 | buf_sprintf("unable to evaluate constant expression")); |
| 8274 | 8303 | return &codegen->invalid_instruction->value; |
| ... | ... | @@ -9012,7 +9041,42 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc |
| 9012 | 9041 | return false; |
| 9013 | 9042 | } |
| 9014 | 9043 | |
| 9015 | ConstExprValue *const_val = ir_resolve_const(ira, instruction, UndefBad); | |
| 9044 | ConstExprValue *const_val = ir_resolve_const(ira, instruction, LazyOkNoUndef); | |
| 9045 | if (const_val == nullptr) | |
| 9046 | return false; | |
| 9047 | ||
| 9048 | if (const_val->special == ConstValSpecialLazy) { | |
| 9049 | switch (const_val->data.x_lazy->id) { | |
| 9050 | case LazyValueIdAlignOf: { | |
| 9051 | // This is guaranteed to fit into a u29 | |
| 9052 | if (other_type->id == ZigTypeIdComptimeInt) | |
| 9053 | return true; | |
| 9054 | size_t align_bits = get_align_amt_type(ira->codegen)->data.integral.bit_count; | |
| 9055 | if (other_type->id == ZigTypeIdInt && !other_type->data.integral.is_signed && | |
| 9056 | other_type->data.integral.bit_count >= align_bits) | |
| 9057 | { | |
| 9058 | return true; | |
| 9059 | } | |
| 9060 | break; | |
| 9061 | } | |
| 9062 | case LazyValueIdSizeOf: { | |
| 9063 | // This is guaranteed to fit into a usize | |
| 9064 | if (other_type->id == ZigTypeIdComptimeInt) | |
| 9065 | return true; | |
| 9066 | size_t usize_bits = ira->codegen->builtin_types.entry_usize->data.integral.bit_count; | |
| 9067 | if (other_type->id == ZigTypeIdInt && !other_type->data.integral.is_signed && | |
| 9068 | other_type->data.integral.bit_count >= usize_bits) | |
| 9069 | { | |
| 9070 | return true; | |
| 9071 | } | |
| 9072 | break; | |
| 9073 | } | |
| 9074 | default: | |
| 9075 | break; | |
| 9076 | } | |
| 9077 | } | |
| 9078 | ||
| 9079 | const_val = ir_resolve_const(ira, instruction, UndefBad); | |
| 9016 | 9080 | if (const_val == nullptr) |
| 9017 | 9081 | return false; |
| 9018 | 9082 | |
| ... | ... | @@ -10262,7 +10326,7 @@ static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_ |
| 10262 | 10326 | memcpy(dest, src, sizeof(ConstExprValue)); |
| 10263 | 10327 | if (!same_global_refs) { |
| 10264 | 10328 | dest->global_refs = global_refs; |
| 10265 | if (src->special == ConstValSpecialUndef) | |
| 10329 | if (src->special != ConstValSpecialStatic) | |
| 10266 | 10330 | return; |
| 10267 | 10331 | if (dest->type->id == ZigTypeIdStruct) { |
| 10268 | 10332 | dest->data.x_struct.fields = create_const_vals(dest->type->data.structure.src_field_count); |
| ... | ... | @@ -10803,7 +10867,7 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod |
| 10803 | 10867 | fprintf(stderr, "\nSource: "); |
| 10804 | 10868 | ast_render(stderr, node, 4); |
| 10805 | 10869 | fprintf(stderr, "\n{ // (IR)\n"); |
| 10806 | ir_print(codegen, stderr, ir_executable, 2); | |
| 10870 | ir_print(codegen, stderr, ir_executable, 2, 1); | |
| 10807 | 10871 | fprintf(stderr, "}\n"); |
| 10808 | 10872 | } |
| 10809 | 10873 | IrExecutable *analyzed_executable = allocate<IrExecutable>(1); |
| ... | ... | @@ -10824,7 +10888,7 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod |
| 10824 | 10888 | |
| 10825 | 10889 | if (codegen->verbose_ir) { |
| 10826 | 10890 | fprintf(stderr, "{ // (analyzed)\n"); |
| 10827 | ir_print(codegen, stderr, analyzed_executable, 2); | |
| 10891 | ir_print(codegen, stderr, analyzed_executable, 2, 2); | |
| 10828 | 10892 | fprintf(stderr, "}\n"); |
| 10829 | 10893 | } |
| 10830 | 10894 | |
| ... | ... | @@ -11213,7 +11277,7 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi |
| 11213 | 11277 | return ira->codegen->invalid_instruction; |
| 11214 | 11278 | |
| 11215 | 11279 | if (instr_is_comptime(value)) { |
| 11216 | ConstExprValue *val = ir_resolve_const(ira, value, UndefOk); | |
| 11280 | ConstExprValue *val = ir_resolve_const(ira, value, LazyOk); | |
| 11217 | 11281 | if (!val) |
| 11218 | 11282 | return ira->codegen->invalid_instruction; |
| 11219 | 11283 | return ir_get_const_ptr(ira, source_instruction, val, value->value.type, |
| ... | ... | @@ -12125,7 +12189,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 12125 | 12189 | if (wanted_type->id == ZigTypeIdComptimeInt || wanted_type->id == ZigTypeIdInt) { |
| 12126 | 12190 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); |
| 12127 | 12191 | if (actual_type->id == ZigTypeIdComptimeInt || actual_type->id == ZigTypeIdInt) { |
| 12128 | bigint_init_bigint(&result->value.data.x_bigint, &value->value.data.x_bigint); | |
| 12192 | copy_const_val(&result->value, &value->value, false); | |
| 12193 | result->value.type = wanted_type; | |
| 12129 | 12194 | } else { |
| 12130 | 12195 | float_init_bigint(&result->value.data.x_bigint, &value->value); |
| 12131 | 12196 | } |
| ... | ... | @@ -14869,7 +14934,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe |
| 14869 | 14934 | PtrLenSingle, 0, 0, 0, false); |
| 14870 | 14935 | set_up_result_loc_for_inferred_comptime(&alloca_gen->base); |
| 14871 | 14936 | ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec); |
| 14872 | if (fn_entry != nullptr) { | |
| 14937 | if (fn_entry != nullptr && get_scope_typeof(suspend_source_instr->scope) == nullptr) { | |
| 14873 | 14938 | fn_entry->alloca_gen_list.append(alloca_gen); |
| 14874 | 14939 | } |
| 14875 | 14940 | result_loc->written = true; |
| ... | ... | @@ -15200,44 +15265,61 @@ static IrInstruction *ir_analyze_instruction_reset_result(IrAnalyze *ira, IrInst |
| 15200 | 15265 | return ir_const_void(ira, &instruction->base); |
| 15201 | 15266 | } |
| 15202 | 15267 | |
| 15268 | static IrInstruction *get_async_call_result_loc(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, | |
| 15269 | ZigType *fn_ret_type) | |
| 15270 | { | |
| 15271 | ir_assert(call_instruction->is_async_call_builtin, &call_instruction->base); | |
| 15272 | IrInstruction *ret_ptr_uncasted = call_instruction->args[call_instruction->arg_count]->child; | |
| 15273 | if (type_is_invalid(ret_ptr_uncasted->value.type)) | |
| 15274 | return ira->codegen->invalid_instruction; | |
| 15275 | if (ret_ptr_uncasted->value.type->id == ZigTypeIdVoid) { | |
| 15276 | // Result location will be inside the async frame. | |
| 15277 | return nullptr; | |
| 15278 | } | |
| 15279 | return ir_implicit_cast(ira, ret_ptr_uncasted, get_pointer_to_type(ira->codegen, fn_ret_type, false)); | |
| 15280 | } | |
| 15281 | ||
| 15203 | 15282 | static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry, |
| 15204 | 15283 | ZigType *fn_type, IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count, |
| 15205 | 15284 | IrInstruction *casted_new_stack) |
| 15206 | 15285 | { |
| 15207 | if (casted_new_stack != nullptr) { | |
| 15208 | // this is an @asyncCall | |
| 15209 | ||
| 15286 | if (fn_entry == nullptr) { | |
| 15210 | 15287 | if (fn_type->data.fn.fn_type_id.cc != CallingConventionAsync) { |
| 15211 | 15288 | ir_add_error(ira, fn_ref, |
| 15212 | 15289 | buf_sprintf("expected async function, found '%s'", buf_ptr(&fn_type->name))); |
| 15213 | 15290 | return ira->codegen->invalid_instruction; |
| 15214 | 15291 | } |
| 15215 | ||
| 15216 | IrInstruction *ret_ptr = call_instruction->args[call_instruction->arg_count]->child; | |
| 15217 | if (type_is_invalid(ret_ptr->value.type)) | |
| 15292 | if (casted_new_stack == nullptr) { | |
| 15293 | ir_add_error(ira, fn_ref, buf_sprintf("function is not comptime-known; @asyncCall required")); | |
| 15294 | return ira->codegen->invalid_instruction; | |
| 15295 | } | |
| 15296 | } | |
| 15297 | if (casted_new_stack != nullptr) { | |
| 15298 | ZigType *fn_ret_type = fn_type->data.fn.fn_type_id.return_type; | |
| 15299 | IrInstruction *ret_ptr = get_async_call_result_loc(ira, call_instruction, fn_ret_type); | |
| 15300 | if (ret_ptr != nullptr && type_is_invalid(ret_ptr->value.type)) | |
| 15218 | 15301 | return ira->codegen->invalid_instruction; |
| 15219 | 15302 | |
| 15220 | ZigType *anyframe_type = get_any_frame_type(ira->codegen, fn_type->data.fn.fn_type_id.return_type); | |
| 15303 | ZigType *anyframe_type = get_any_frame_type(ira->codegen, fn_ret_type); | |
| 15221 | 15304 | |
| 15222 | IrInstructionCallGen *call_gen = ir_build_call_gen(ira, &call_instruction->base, nullptr, fn_ref, | |
| 15223 | arg_count, casted_args, FnInlineAuto, true, casted_new_stack, ret_ptr, anyframe_type); | |
| 15305 | IrInstructionCallGen *call_gen = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, | |
| 15306 | arg_count, casted_args, FnInlineAuto, true, casted_new_stack, | |
| 15307 | call_instruction->is_async_call_builtin, ret_ptr, anyframe_type); | |
| 15224 | 15308 | return &call_gen->base; |
| 15225 | } else if (fn_entry == nullptr) { | |
| 15226 | ir_add_error(ira, fn_ref, buf_sprintf("function is not comptime-known; @asyncCall required")); | |
| 15227 | return ira->codegen->invalid_instruction; | |
| 15228 | } | |
| 15229 | ||
| 15230 | ZigType *frame_type = get_fn_frame_type(ira->codegen, fn_entry); | |
| 15231 | IrInstruction *result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, | |
| 15232 | frame_type, nullptr, true, true, false); | |
| 15233 | if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { | |
| 15234 | return result_loc; | |
| 15309 | } else { | |
| 15310 | ZigType *frame_type = get_fn_frame_type(ira->codegen, fn_entry); | |
| 15311 | IrInstruction *result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, | |
| 15312 | frame_type, nullptr, true, true, false); | |
| 15313 | if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { | |
| 15314 | return result_loc; | |
| 15315 | } | |
| 15316 | result_loc = ir_implicit_cast(ira, result_loc, get_pointer_to_type(ira->codegen, frame_type, false)); | |
| 15317 | if (type_is_invalid(result_loc->value.type)) | |
| 15318 | return ira->codegen->invalid_instruction; | |
| 15319 | return &ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, arg_count, | |
| 15320 | casted_args, FnInlineAuto, true, casted_new_stack, call_instruction->is_async_call_builtin, | |
| 15321 | result_loc, frame_type)->base; | |
| 15235 | 15322 | } |
| 15236 | result_loc = ir_implicit_cast(ira, result_loc, get_pointer_to_type(ira->codegen, frame_type, false)); | |
| 15237 | if (type_is_invalid(result_loc->value.type)) | |
| 15238 | return ira->codegen->invalid_instruction; | |
| 15239 | return &ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, arg_count, | |
| 15240 | casted_args, FnInlineAuto, true, nullptr, result_loc, frame_type)->base; | |
| 15241 | 15323 | } |
| 15242 | 15324 | static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node, |
| 15243 | 15325 | IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i) |
| ... | ... | @@ -15301,7 +15383,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod |
| 15301 | 15383 | } |
| 15302 | 15384 | } |
| 15303 | 15385 | |
| 15304 | bool comptime_arg = param_decl_node->data.param_decl.is_inline || | |
| 15386 | bool comptime_arg = param_decl_node->data.param_decl.is_comptime || | |
| 15305 | 15387 | casted_arg->value.type->id == ZigTypeIdComptimeInt || casted_arg->value.type->id == ZigTypeIdComptimeFloat; |
| 15306 | 15388 | |
| 15307 | 15389 | ConstExprValue *arg_val; |
| ... | ... | @@ -15746,16 +15828,27 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 15746 | 15828 | |
| 15747 | 15829 | IrInstruction *casted_new_stack = nullptr; |
| 15748 | 15830 | if (call_instruction->new_stack != nullptr) { |
| 15749 | ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, | |
| 15750 | false, false, PtrLenUnknown, target_fn_align(ira->codegen->zig_target), 0, 0, false); | |
| 15751 | ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr); | |
| 15752 | 15831 | IrInstruction *new_stack = call_instruction->new_stack->child; |
| 15753 | 15832 | if (type_is_invalid(new_stack->value.type)) |
| 15754 | 15833 | return ira->codegen->invalid_instruction; |
| 15755 | 15834 | |
| 15756 | casted_new_stack = ir_implicit_cast(ira, new_stack, u8_slice); | |
| 15757 | if (type_is_invalid(casted_new_stack->value.type)) | |
| 15758 | return ira->codegen->invalid_instruction; | |
| 15835 | if (call_instruction->is_async_call_builtin && | |
| 15836 | fn_entry != nullptr && new_stack->value.type->id == ZigTypeIdPointer && | |
| 15837 | new_stack->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame) | |
| 15838 | { | |
| 15839 | ZigType *needed_frame_type = get_pointer_to_type(ira->codegen, | |
| 15840 | get_fn_frame_type(ira->codegen, fn_entry), false); | |
| 15841 | casted_new_stack = ir_implicit_cast(ira, new_stack, needed_frame_type); | |
| 15842 | if (type_is_invalid(casted_new_stack->value.type)) | |
| 15843 | return ira->codegen->invalid_instruction; | |
| 15844 | } else { | |
| 15845 | ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, | |
| 15846 | false, false, PtrLenUnknown, target_fn_align(ira->codegen->zig_target), 0, 0, false); | |
| 15847 | ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr); | |
| 15848 | casted_new_stack = ir_implicit_cast(ira, new_stack, u8_slice); | |
| 15849 | if (type_is_invalid(casted_new_stack->value.type)) | |
| 15850 | return ira->codegen->invalid_instruction; | |
| 15851 | } | |
| 15759 | 15852 | } |
| 15760 | 15853 | |
| 15761 | 15854 | if (fn_type->data.fn.is_generic) { |
| ... | ... | @@ -15965,8 +16058,24 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 15965 | 16058 | } |
| 15966 | 16059 | |
| 15967 | 16060 | FnTypeId *impl_fn_type_id = &impl_fn->type_entry->data.fn.fn_type_id; |
| 16061 | ||
| 16062 | if (fn_type_can_fail(impl_fn_type_id)) { | |
| 16063 | parent_fn_entry->calls_or_awaits_errorable_fn = true; | |
| 16064 | } | |
| 16065 | ||
| 16066 | size_t impl_param_count = impl_fn_type_id->param_count; | |
| 16067 | if (call_instruction->is_async) { | |
| 16068 | IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry, | |
| 16069 | nullptr, casted_args, impl_param_count, casted_new_stack); | |
| 16070 | return ir_finish_anal(ira, result); | |
| 16071 | } | |
| 16072 | ||
| 15968 | 16073 | IrInstruction *result_loc; |
| 15969 | if (handle_is_ptr(impl_fn_type_id->return_type)) { | |
| 16074 | if (call_instruction->is_async_call_builtin) { | |
| 16075 | result_loc = get_async_call_result_loc(ira, call_instruction, impl_fn_type_id->return_type); | |
| 16076 | if (result_loc != nullptr && type_is_invalid(result_loc->value.type)) | |
| 16077 | return ira->codegen->invalid_instruction; | |
| 16078 | } else if (handle_is_ptr(impl_fn_type_id->return_type)) { | |
| 15970 | 16079 | result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, |
| 15971 | 16080 | impl_fn_type_id->return_type, nullptr, true, true, false); |
| 15972 | 16081 | if (result_loc != nullptr) { |
| ... | ... | @@ -15982,17 +16091,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 15982 | 16091 | result_loc = nullptr; |
| 15983 | 16092 | } |
| 15984 | 16093 | |
| 15985 | if (fn_type_can_fail(impl_fn_type_id)) { | |
| 15986 | parent_fn_entry->calls_or_awaits_errorable_fn = true; | |
| 15987 | } | |
| 15988 | ||
| 15989 | size_t impl_param_count = impl_fn_type_id->param_count; | |
| 15990 | if (call_instruction->is_async) { | |
| 15991 | IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry, | |
| 15992 | nullptr, casted_args, impl_param_count, casted_new_stack); | |
| 15993 | return ir_finish_anal(ira, result); | |
| 15994 | } | |
| 15995 | ||
| 15996 | 16094 | if (impl_fn_type_id->cc == CallingConventionAsync && parent_fn_entry->inferred_async_node == nullptr) { |
| 15997 | 16095 | parent_fn_entry->inferred_async_node = fn_ref->source_node; |
| 15998 | 16096 | parent_fn_entry->inferred_async_fn = impl_fn; |
| ... | ... | @@ -16000,10 +16098,12 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 16000 | 16098 | |
| 16001 | 16099 | IrInstructionCallGen *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, |
| 16002 | 16100 | impl_fn, nullptr, impl_param_count, casted_args, fn_inline, |
| 16003 | false, casted_new_stack, result_loc, | |
| 16101 | false, casted_new_stack, call_instruction->is_async_call_builtin, result_loc, | |
| 16004 | 16102 | impl_fn_type_id->return_type); |
| 16005 | 16103 | |
| 16006 | parent_fn_entry->call_list.append(new_call_instruction); | |
| 16104 | if (get_scope_typeof(call_instruction->base.scope) == nullptr) { | |
| 16105 | parent_fn_entry->call_list.append(new_call_instruction); | |
| 16106 | } | |
| 16007 | 16107 | |
| 16008 | 16108 | return ir_finish_anal(ira, &new_call_instruction->base); |
| 16009 | 16109 | } |
| ... | ... | @@ -16123,7 +16223,11 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 16123 | 16223 | } |
| 16124 | 16224 | |
| 16125 | 16225 | IrInstruction *result_loc; |
| 16126 | if (handle_is_ptr(return_type)) { | |
| 16226 | if (call_instruction->is_async_call_builtin) { | |
| 16227 | result_loc = get_async_call_result_loc(ira, call_instruction, return_type); | |
| 16228 | if (result_loc != nullptr && type_is_invalid(result_loc->value.type)) | |
| 16229 | return ira->codegen->invalid_instruction; | |
| 16230 | } else if (handle_is_ptr(return_type)) { | |
| 16127 | 16231 | result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, |
| 16128 | 16232 | return_type, nullptr, true, true, false); |
| 16129 | 16233 | if (result_loc != nullptr) { |
| ... | ... | @@ -16141,8 +16245,10 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 16141 | 16245 | |
| 16142 | 16246 | IrInstructionCallGen *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, |
| 16143 | 16247 | call_param_count, casted_args, fn_inline, false, casted_new_stack, |
| 16144 | result_loc, return_type); | |
| 16145 | parent_fn_entry->call_list.append(new_call_instruction); | |
| 16248 | call_instruction->is_async_call_builtin, result_loc, return_type); | |
| 16249 | if (get_scope_typeof(call_instruction->base.scope) == nullptr) { | |
| 16250 | parent_fn_entry->call_list.append(new_call_instruction); | |
| 16251 | } | |
| 16146 | 16252 | return ir_finish_anal(ira, &new_call_instruction->base); |
| 16147 | 16253 | } |
| 16148 | 16254 | |
| ... | ... | @@ -17594,6 +17700,11 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc |
| 17594 | 17700 | ConstExprValue *child_val = const_ptr_pointee(ira, ira->codegen, container_ptr_val, source_node); |
| 17595 | 17701 | if (child_val == nullptr) |
| 17596 | 17702 | return ira->codegen->invalid_instruction; |
| 17703 | if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, | |
| 17704 | field_ptr_instruction->base.source_node, child_val, UndefBad))) | |
| 17705 | { | |
| 17706 | return ira->codegen->invalid_instruction; | |
| 17707 | } | |
| 17597 | 17708 | ZigType *child_type = child_val->data.x_type; |
| 17598 | 17709 | |
| 17599 | 17710 | if (type_is_invalid(child_type)) { |
| ... | ... | @@ -21293,8 +21404,10 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru |
| 21293 | 21404 | src_ptr_align = get_abi_alignment(ira->codegen, target->value.type); |
| 21294 | 21405 | } |
| 21295 | 21406 | |
| 21296 | if ((err = type_resolve(ira->codegen, dest_child_type, ResolveStatusSizeKnown))) | |
| 21297 | return ira->codegen->invalid_instruction; | |
| 21407 | if (src_ptr_align != 0) { | |
| 21408 | if ((err = type_resolve(ira->codegen, dest_child_type, ResolveStatusAlignmentKnown))) | |
| 21409 | return ira->codegen->invalid_instruction; | |
| 21410 | } | |
| 21298 | 21411 | |
| 21299 | 21412 | ZigType *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, dest_child_type, |
| 21300 | 21413 | src_ptr_const, src_ptr_volatile, PtrLenUnknown, |
| ... | ... | @@ -21337,6 +21450,8 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru |
| 21337 | 21450 | } |
| 21338 | 21451 | |
| 21339 | 21452 | if (have_known_len) { |
| 21453 | if ((err = type_resolve(ira->codegen, dest_child_type, ResolveStatusSizeKnown))) | |
| 21454 | return ira->codegen->invalid_instruction; | |
| 21340 | 21455 | uint64_t child_type_size = type_size(ira->codegen, dest_child_type); |
| 21341 | 21456 | uint64_t remainder = known_len % child_type_size; |
| 21342 | 21457 | if (remainder != 0) { |
| ... | ... | @@ -23963,15 +24078,23 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct |
| 23963 | 24078 | } |
| 23964 | 24079 | |
| 23965 | 24080 | static IrInstruction *ir_analyze_instruction_align_cast(IrAnalyze *ira, IrInstructionAlignCast *instruction) { |
| 23966 | uint32_t align_bytes; | |
| 23967 | IrInstruction *align_bytes_inst = instruction->align_bytes->child; | |
| 23968 | if (!ir_resolve_align(ira, align_bytes_inst, nullptr, &align_bytes)) | |
| 23969 | return ira->codegen->invalid_instruction; | |
| 23970 | ||
| 23971 | 24081 | IrInstruction *target = instruction->target->child; |
| 23972 | 24082 | if (type_is_invalid(target->value.type)) |
| 23973 | 24083 | return ira->codegen->invalid_instruction; |
| 23974 | 24084 | |
| 24085 | ZigType *elem_type = nullptr; | |
| 24086 | if (is_slice(target->value.type)) { | |
| 24087 | ZigType *slice_ptr_type = target->value.type->data.structure.fields[slice_ptr_index].type_entry; | |
| 24088 | elem_type = slice_ptr_type->data.pointer.child_type; | |
| 24089 | } else if (target->value.type->id == ZigTypeIdPointer) { | |
| 24090 | elem_type = target->value.type->data.pointer.child_type; | |
| 24091 | } | |
| 24092 | ||
| 24093 | uint32_t align_bytes; | |
| 24094 | IrInstruction *align_bytes_inst = instruction->align_bytes->child; | |
| 24095 | if (!ir_resolve_align(ira, align_bytes_inst, elem_type, &align_bytes)) | |
| 24096 | return ira->codegen->invalid_instruction; | |
| 24097 | ||
| 23975 | 24098 | IrInstruction *result = ir_align_cast(ira, target, align_bytes, true); |
| 23976 | 24099 | if (type_is_invalid(result->value.type)) |
| 23977 | 24100 | return ira->codegen->invalid_instruction; |
| ... | ... | @@ -25644,7 +25767,7 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) { |
| 25644 | 25767 | } |
| 25645 | 25768 | |
| 25646 | 25769 | val->special = ConstValSpecialStatic; |
| 25647 | assert(val->type->id == ZigTypeIdComptimeInt); | |
| 25770 | assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt); | |
| 25648 | 25771 | bigint_init_unsigned(&val->data.x_bigint, align_in_bytes); |
| 25649 | 25772 | return ErrorNone; |
| 25650 | 25773 | } |
| ... | ... | @@ -25699,7 +25822,7 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) { |
| 25699 | 25822 | } |
| 25700 | 25823 | |
| 25701 | 25824 | val->special = ConstValSpecialStatic; |
| 25702 | assert(val->type->id == ZigTypeIdComptimeInt); | |
| 25825 | assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt); | |
| 25703 | 25826 | bigint_init_unsigned(&val->data.x_bigint, abi_size); |
| 25704 | 25827 | return ErrorNone; |
| 25705 | 25828 | } |
| ... | ... | @@ -25885,7 +26008,7 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) { |
| 25885 | 26008 | Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ConstExprValue *val) { |
| 25886 | 26009 | Error err; |
| 25887 | 26010 | if ((err = ir_resolve_lazy_raw(source_node, val))) { |
| 25888 | if (codegen->trace_err != nullptr && !source_node->already_traced_this_node) { | |
| 26011 | if (codegen->trace_err != nullptr && source_node != nullptr && !source_node->already_traced_this_node) { | |
| 25889 | 26012 | source_node->already_traced_this_node = true; |
| 25890 | 26013 | codegen->trace_err = add_error_note(codegen, codegen->trace_err, source_node, |
| 25891 | 26014 | buf_create_from_str("referenced here")); |
src/ir_print.cpp+377-8| ... | ... | @@ -10,27 +10,374 @@ |
| 10 | 10 | #include "ir_print.hpp" |
| 11 | 11 | #include "os.hpp" |
| 12 | 12 | |
| 13 | static uint32_t hash_instruction_ptr(IrInstruction* instruction) { | |
| 14 | return (uint32_t)(uintptr_t)instruction; | |
| 15 | } | |
| 16 | ||
| 17 | static bool instruction_ptr_equal(IrInstruction* a, IrInstruction* b) { | |
| 18 | return a == b; | |
| 19 | } | |
| 20 | ||
| 21 | using InstructionSet = HashMap<IrInstruction*, uint8_t, hash_instruction_ptr, instruction_ptr_equal>; | |
| 22 | using InstructionList = ZigList<IrInstruction*>; | |
| 23 | ||
| 13 | 24 | struct IrPrint { |
| 25 | size_t pass_num; | |
| 14 | 26 | CodeGen *codegen; |
| 15 | 27 | FILE *f; |
| 16 | 28 | int indent; |
| 17 | 29 | int indent_size; |
| 30 | ||
| 31 | // When printing pass 2 instructions referenced var instructions are not | |
| 32 | // present in the instruction list. Thus we track which instructions | |
| 33 | // are printed (per executable) and after each pass 2 instruction those | |
| 34 | // var instructions are rendered in a trailing fashion. | |
| 35 | InstructionSet printed; | |
| 36 | InstructionList pending; | |
| 18 | 37 | }; |
| 19 | 38 | |
| 20 | 39 | static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction); |
| 21 | 40 | |
| 41 | static const char* ir_instruction_type_str(IrInstruction* instruction) { | |
| 42 | switch (instruction->id) { | |
| 43 | case IrInstructionIdInvalid: | |
| 44 | return "Invalid"; | |
| 45 | case IrInstructionIdDeclVarSrc: | |
| 46 | return "DeclVarSrc"; | |
| 47 | case IrInstructionIdDeclVarGen: | |
| 48 | return "DeclVarGen"; | |
| 49 | case IrInstructionIdBr: | |
| 50 | return "Br"; | |
| 51 | case IrInstructionIdCondBr: | |
| 52 | return "CondBr"; | |
| 53 | case IrInstructionIdSwitchBr: | |
| 54 | return "SwitchBr"; | |
| 55 | case IrInstructionIdSwitchVar: | |
| 56 | return "SwitchVar"; | |
| 57 | case IrInstructionIdSwitchElseVar: | |
| 58 | return "SwitchElseVar"; | |
| 59 | case IrInstructionIdSwitchTarget: | |
| 60 | return "SwitchTarget"; | |
| 61 | case IrInstructionIdPhi: | |
| 62 | return "Phi"; | |
| 63 | case IrInstructionIdUnOp: | |
| 64 | return "UnOp"; | |
| 65 | case IrInstructionIdBinOp: | |
| 66 | return "BinOp"; | |
| 67 | case IrInstructionIdLoadPtr: | |
| 68 | return "LoadPtr"; | |
| 69 | case IrInstructionIdLoadPtrGen: | |
| 70 | return "LoadPtrGen"; | |
| 71 | case IrInstructionIdStorePtr: | |
| 72 | return "StorePtr"; | |
| 73 | case IrInstructionIdFieldPtr: | |
| 74 | return "FieldPtr"; | |
| 75 | case IrInstructionIdStructFieldPtr: | |
| 76 | return "StructFieldPtr"; | |
| 77 | case IrInstructionIdUnionFieldPtr: | |
| 78 | return "UnionFieldPtr"; | |
| 79 | case IrInstructionIdElemPtr: | |
| 80 | return "ElemPtr"; | |
| 81 | case IrInstructionIdVarPtr: | |
| 82 | return "VarPtr"; | |
| 83 | case IrInstructionIdReturnPtr: | |
| 84 | return "ReturnPtr"; | |
| 85 | case IrInstructionIdCallSrc: | |
| 86 | return "CallSrc"; | |
| 87 | case IrInstructionIdCallGen: | |
| 88 | return "CallGen"; | |
| 89 | case IrInstructionIdConst: | |
| 90 | return "Const"; | |
| 91 | case IrInstructionIdReturn: | |
| 92 | return "Return"; | |
| 93 | case IrInstructionIdCast: | |
| 94 | return "Cast"; | |
| 95 | case IrInstructionIdResizeSlice: | |
| 96 | return "ResizeSlice"; | |
| 97 | case IrInstructionIdContainerInitList: | |
| 98 | return "ContainerInitList"; | |
| 99 | case IrInstructionIdContainerInitFields: | |
| 100 | return "ContainerInitFields"; | |
| 101 | case IrInstructionIdUnreachable: | |
| 102 | return "Unreachable"; | |
| 103 | case IrInstructionIdTypeOf: | |
| 104 | return "TypeOf"; | |
| 105 | case IrInstructionIdSetCold: | |
| 106 | return "SetCold"; | |
| 107 | case IrInstructionIdSetRuntimeSafety: | |
| 108 | return "SetRuntimeSafety"; | |
| 109 | case IrInstructionIdSetFloatMode: | |
| 110 | return "SetFloatMode"; | |
| 111 | case IrInstructionIdArrayType: | |
| 112 | return "ArrayType"; | |
| 113 | case IrInstructionIdAnyFrameType: | |
| 114 | return "AnyFrameType"; | |
| 115 | case IrInstructionIdSliceType: | |
| 116 | return "SliceType"; | |
| 117 | case IrInstructionIdGlobalAsm: | |
| 118 | return "GlobalAsm"; | |
| 119 | case IrInstructionIdAsm: | |
| 120 | return "Asm"; | |
| 121 | case IrInstructionIdSizeOf: | |
| 122 | return "SizeOf"; | |
| 123 | case IrInstructionIdTestNonNull: | |
| 124 | return "TestNonNull"; | |
| 125 | case IrInstructionIdOptionalUnwrapPtr: | |
| 126 | return "OptionalUnwrapPtr"; | |
| 127 | case IrInstructionIdOptionalWrap: | |
| 128 | return "OptionalWrap"; | |
| 129 | case IrInstructionIdUnionTag: | |
| 130 | return "UnionTag"; | |
| 131 | case IrInstructionIdClz: | |
| 132 | return "Clz"; | |
| 133 | case IrInstructionIdCtz: | |
| 134 | return "Ctz"; | |
| 135 | case IrInstructionIdPopCount: | |
| 136 | return "PopCount"; | |
| 137 | case IrInstructionIdBswap: | |
| 138 | return "Bswap"; | |
| 139 | case IrInstructionIdBitReverse: | |
| 140 | return "BitReverse"; | |
| 141 | case IrInstructionIdImport: | |
| 142 | return "Import"; | |
| 143 | case IrInstructionIdCImport: | |
| 144 | return "CImport"; | |
| 145 | case IrInstructionIdCInclude: | |
| 146 | return "CInclude"; | |
| 147 | case IrInstructionIdCDefine: | |
| 148 | return "CDefine"; | |
| 149 | case IrInstructionIdCUndef: | |
| 150 | return "CUndef"; | |
| 151 | case IrInstructionIdRef: | |
| 152 | return "Ref"; | |
| 153 | case IrInstructionIdRefGen: | |
| 154 | return "RefGen"; | |
| 155 | case IrInstructionIdCompileErr: | |
| 156 | return "CompileErr"; | |
| 157 | case IrInstructionIdCompileLog: | |
| 158 | return "CompileLog"; | |
| 159 | case IrInstructionIdErrName: | |
| 160 | return "ErrName"; | |
| 161 | case IrInstructionIdEmbedFile: | |
| 162 | return "EmbedFile"; | |
| 163 | case IrInstructionIdCmpxchgSrc: | |
| 164 | return "CmpxchgSrc"; | |
| 165 | case IrInstructionIdCmpxchgGen: | |
| 166 | return "CmpxchgGen"; | |
| 167 | case IrInstructionIdFence: | |
| 168 | return "Fence"; | |
| 169 | case IrInstructionIdTruncate: | |
| 170 | return "Truncate"; | |
| 171 | case IrInstructionIdIntCast: | |
| 172 | return "IntCast"; | |
| 173 | case IrInstructionIdFloatCast: | |
| 174 | return "FloatCast"; | |
| 175 | case IrInstructionIdIntToFloat: | |
| 176 | return "IntToFloat"; | |
| 177 | case IrInstructionIdFloatToInt: | |
| 178 | return "FloatToInt"; | |
| 179 | case IrInstructionIdBoolToInt: | |
| 180 | return "BoolToInt"; | |
| 181 | case IrInstructionIdIntType: | |
| 182 | return "IntType"; | |
| 183 | case IrInstructionIdVectorType: | |
| 184 | return "VectorType"; | |
| 185 | case IrInstructionIdBoolNot: | |
| 186 | return "BoolNot"; | |
| 187 | case IrInstructionIdMemset: | |
| 188 | return "Memset"; | |
| 189 | case IrInstructionIdMemcpy: | |
| 190 | return "Memcpy"; | |
| 191 | case IrInstructionIdSliceSrc: | |
| 192 | return "SliceSrc"; | |
| 193 | case IrInstructionIdSliceGen: | |
| 194 | return "SliceGen"; | |
| 195 | case IrInstructionIdMemberCount: | |
| 196 | return "MemberCount"; | |
| 197 | case IrInstructionIdMemberType: | |
| 198 | return "MemberType"; | |
| 199 | case IrInstructionIdMemberName: | |
| 200 | return "MemberName"; | |
| 201 | case IrInstructionIdBreakpoint: | |
| 202 | return "Breakpoint"; | |
| 203 | case IrInstructionIdReturnAddress: | |
| 204 | return "ReturnAddress"; | |
| 205 | case IrInstructionIdFrameAddress: | |
| 206 | return "FrameAddress"; | |
| 207 | case IrInstructionIdFrameHandle: | |
| 208 | return "FrameHandle"; | |
| 209 | case IrInstructionIdFrameType: | |
| 210 | return "FrameType"; | |
| 211 | case IrInstructionIdFrameSizeSrc: | |
| 212 | return "FrameSizeSrc"; | |
| 213 | case IrInstructionIdFrameSizeGen: | |
| 214 | return "FrameSizeGen"; | |
| 215 | case IrInstructionIdAlignOf: | |
| 216 | return "AlignOf"; | |
| 217 | case IrInstructionIdOverflowOp: | |
| 218 | return "OverflowOp"; | |
| 219 | case IrInstructionIdTestErrSrc: | |
| 220 | return "TestErrSrc"; | |
| 221 | case IrInstructionIdTestErrGen: | |
| 222 | return "TestErrGen"; | |
| 223 | case IrInstructionIdMulAdd: | |
| 224 | return "MulAdd"; | |
| 225 | case IrInstructionIdFloatOp: | |
| 226 | return "FloatOp"; | |
| 227 | case IrInstructionIdUnwrapErrCode: | |
| 228 | return "UnwrapErrCode"; | |
| 229 | case IrInstructionIdUnwrapErrPayload: | |
| 230 | return "UnwrapErrPayload"; | |
| 231 | case IrInstructionIdErrWrapCode: | |
| 232 | return "ErrWrapCode"; | |
| 233 | case IrInstructionIdErrWrapPayload: | |
| 234 | return "ErrWrapPayload"; | |
| 235 | case IrInstructionIdFnProto: | |
| 236 | return "FnProto"; | |
| 237 | case IrInstructionIdTestComptime: | |
| 238 | return "TestComptime"; | |
| 239 | case IrInstructionIdPtrCastSrc: | |
| 240 | return "PtrCastSrc"; | |
| 241 | case IrInstructionIdPtrCastGen: | |
| 242 | return "PtrCastGen"; | |
| 243 | case IrInstructionIdBitCastSrc: | |
| 244 | return "BitCastSrc"; | |
| 245 | case IrInstructionIdBitCastGen: | |
| 246 | return "BitCastGen"; | |
| 247 | case IrInstructionIdWidenOrShorten: | |
| 248 | return "WidenOrShorten"; | |
| 249 | case IrInstructionIdIntToPtr: | |
| 250 | return "IntToPtr"; | |
| 251 | case IrInstructionIdPtrToInt: | |
| 252 | return "PtrToInt"; | |
| 253 | case IrInstructionIdIntToEnum: | |
| 254 | return "IntToEnum"; | |
| 255 | case IrInstructionIdEnumToInt: | |
| 256 | return "EnumToInt"; | |
| 257 | case IrInstructionIdIntToErr: | |
| 258 | return "IntToErr"; | |
| 259 | case IrInstructionIdErrToInt: | |
| 260 | return "ErrToInt"; | |
| 261 | case IrInstructionIdCheckSwitchProngs: | |
| 262 | return "CheckSwitchProngs"; | |
| 263 | case IrInstructionIdCheckStatementIsVoid: | |
| 264 | return "CheckStatementIsVoid"; | |
| 265 | case IrInstructionIdTypeName: | |
| 266 | return "TypeName"; | |
| 267 | case IrInstructionIdDeclRef: | |
| 268 | return "DeclRef"; | |
| 269 | case IrInstructionIdPanic: | |
| 270 | return "Panic"; | |
| 271 | case IrInstructionIdTagName: | |
| 272 | return "TagName"; | |
| 273 | case IrInstructionIdTagType: | |
| 274 | return "TagType"; | |
| 275 | case IrInstructionIdFieldParentPtr: | |
| 276 | return "FieldParentPtr"; | |
| 277 | case IrInstructionIdByteOffsetOf: | |
| 278 | return "ByteOffsetOf"; | |
| 279 | case IrInstructionIdBitOffsetOf: | |
| 280 | return "BitOffsetOf"; | |
| 281 | case IrInstructionIdTypeInfo: | |
| 282 | return "TypeInfo"; | |
| 283 | case IrInstructionIdHasField: | |
| 284 | return "HasField"; | |
| 285 | case IrInstructionIdTypeId: | |
| 286 | return "TypeId"; | |
| 287 | case IrInstructionIdSetEvalBranchQuota: | |
| 288 | return "SetEvalBranchQuota"; | |
| 289 | case IrInstructionIdPtrType: | |
| 290 | return "PtrType"; | |
| 291 | case IrInstructionIdAlignCast: | |
| 292 | return "AlignCast"; | |
| 293 | case IrInstructionIdImplicitCast: | |
| 294 | return "ImplicitCast"; | |
| 295 | case IrInstructionIdResolveResult: | |
| 296 | return "ResolveResult"; | |
| 297 | case IrInstructionIdResetResult: | |
| 298 | return "ResetResult"; | |
| 299 | case IrInstructionIdOpaqueType: | |
| 300 | return "OpaqueType"; | |
| 301 | case IrInstructionIdSetAlignStack: | |
| 302 | return "SetAlignStack"; | |
| 303 | case IrInstructionIdArgType: | |
| 304 | return "ArgType"; | |
| 305 | case IrInstructionIdExport: | |
| 306 | return "Export"; | |
| 307 | case IrInstructionIdErrorReturnTrace: | |
| 308 | return "ErrorReturnTrace"; | |
| 309 | case IrInstructionIdErrorUnion: | |
| 310 | return "ErrorUnion"; | |
| 311 | case IrInstructionIdAtomicRmw: | |
| 312 | return "AtomicRmw"; | |
| 313 | case IrInstructionIdAtomicLoad: | |
| 314 | return "AtomicLoad"; | |
| 315 | case IrInstructionIdSaveErrRetAddr: | |
| 316 | return "SaveErrRetAddr"; | |
| 317 | case IrInstructionIdAddImplicitReturnType: | |
| 318 | return "AddImplicitReturnType"; | |
| 319 | case IrInstructionIdErrSetCast: | |
| 320 | return "ErrSetCast"; | |
| 321 | case IrInstructionIdToBytes: | |
| 322 | return "ToBytes"; | |
| 323 | case IrInstructionIdFromBytes: | |
| 324 | return "FromBytes"; | |
| 325 | case IrInstructionIdCheckRuntimeScope: | |
| 326 | return "CheckRuntimeScope"; | |
| 327 | case IrInstructionIdVectorToArray: | |
| 328 | return "VectorToArray"; | |
| 329 | case IrInstructionIdArrayToVector: | |
| 330 | return "ArrayToVector"; | |
| 331 | case IrInstructionIdAssertZero: | |
| 332 | return "AssertZero"; | |
| 333 | case IrInstructionIdAssertNonNull: | |
| 334 | return "AssertNonNull"; | |
| 335 | case IrInstructionIdHasDecl: | |
| 336 | return "HasDecl"; | |
| 337 | case IrInstructionIdUndeclaredIdent: | |
| 338 | return "UndeclaredIdent"; | |
| 339 | case IrInstructionIdAllocaSrc: | |
| 340 | return "AllocaSrc"; | |
| 341 | case IrInstructionIdAllocaGen: | |
| 342 | return "AllocaGen"; | |
| 343 | case IrInstructionIdEndExpr: | |
| 344 | return "EndExpr"; | |
| 345 | case IrInstructionIdPtrOfArrayToSlice: | |
| 346 | return "PtrOfArrayToSlice"; | |
| 347 | case IrInstructionIdUnionInitNamedField: | |
| 348 | return "UnionInitNamedField"; | |
| 349 | case IrInstructionIdSuspendBegin: | |
| 350 | return "SuspendBegin"; | |
| 351 | case IrInstructionIdSuspendFinish: | |
| 352 | return "SuspendFinish"; | |
| 353 | case IrInstructionIdAwaitSrc: | |
| 354 | return "AwaitSrc"; | |
| 355 | case IrInstructionIdAwaitGen: | |
| 356 | return "AwaitGen"; | |
| 357 | case IrInstructionIdResume: | |
| 358 | return "Resume"; | |
| 359 | case IrInstructionIdSpillBegin: | |
| 360 | return "SpillBegin"; | |
| 361 | case IrInstructionIdSpillEnd: | |
| 362 | return "SpillEnd"; | |
| 363 | } | |
| 364 | zig_unreachable(); | |
| 365 | } | |
| 366 | ||
| 22 | 367 | static void ir_print_indent(IrPrint *irp) { |
| 23 | 368 | for (int i = 0; i < irp->indent; i += 1) { |
| 24 | 369 | fprintf(irp->f, " "); |
| 25 | 370 | } |
| 26 | 371 | } |
| 27 | 372 | |
| 28 | static void ir_print_prefix(IrPrint *irp, IrInstruction *instruction) { | |
| 373 | static void ir_print_prefix(IrPrint *irp, IrInstruction *instruction, bool trailing) { | |
| 29 | 374 | ir_print_indent(irp); |
| 375 | const char mark = trailing ? ':' : '#'; | |
| 30 | 376 | const char *type_name = instruction->value.type ? buf_ptr(&instruction->value.type->name) : "(unknown)"; |
| 31 | 377 | const char *ref_count = ir_has_side_effects(instruction) ? |
| 32 | 378 | "-" : buf_ptr(buf_sprintf("%" ZIG_PRI_usize "", instruction->ref_count)); |
| 33 | fprintf(irp->f, "#%-3zu| %-12s| %-2s| ", instruction->debug_id, type_name, ref_count); | |
| 379 | fprintf(irp->f, "%c%-3zu| %-22s| %-12s| %-2s| ", mark, instruction->debug_id, | |
| 380 | ir_instruction_type_str(instruction), type_name, ref_count); | |
| 34 | 381 | } |
| 35 | 382 | |
| 36 | 383 | static void ir_print_const_value(IrPrint *irp, ConstExprValue *const_val) { |
| ... | ... | @@ -42,6 +389,10 @@ static void ir_print_const_value(IrPrint *irp, ConstExprValue *const_val) { |
| 42 | 389 | |
| 43 | 390 | static void ir_print_var_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 44 | 391 | fprintf(irp->f, "#%" ZIG_PRI_usize "", instruction->debug_id); |
| 392 | if (irp->pass_num == 2 && irp->printed.maybe_get(instruction) == nullptr) { | |
| 393 | irp->printed.put(instruction, 0); | |
| 394 | irp->pending.append(instruction); | |
| 395 | } | |
| 45 | 396 | } |
| 46 | 397 | |
| 47 | 398 | static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction) { |
| ... | ... | @@ -49,6 +400,7 @@ static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction) |
| 49 | 400 | fprintf(irp->f, "(null)"); |
| 50 | 401 | return; |
| 51 | 402 | } |
| 403 | ||
| 52 | 404 | if (instruction->value.special != ConstValSpecialRuntime) { |
| 53 | 405 | ir_print_const_value(irp, &instruction->value); |
| 54 | 406 | } else { |
| ... | ... | @@ -1550,8 +1902,8 @@ static void ir_print_spill_end(IrPrint *irp, IrInstructionSpillEnd *instruction) |
| 1550 | 1902 | fprintf(irp->f, ")"); |
| 1551 | 1903 | } |
| 1552 | 1904 | |
| 1553 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | |
| 1554 | ir_print_prefix(irp, instruction); | |
| 1905 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool trailing) { | |
| 1906 | ir_print_prefix(irp, instruction, trailing); | |
| 1555 | 1907 | switch (instruction->id) { |
| 1556 | 1908 | case IrInstructionIdInvalid: |
| 1557 | 1909 | zig_unreachable(); |
| ... | ... | @@ -2036,31 +2388,48 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 2036 | 2388 | fprintf(irp->f, "\n"); |
| 2037 | 2389 | } |
| 2038 | 2390 | |
| 2039 | void ir_print(CodeGen *codegen, FILE *f, IrExecutable *executable, int indent_size) { | |
| 2391 | void ir_print(CodeGen *codegen, FILE *f, IrExecutable *executable, int indent_size, size_t pass_num) { | |
| 2040 | 2392 | IrPrint ir_print = {}; |
| 2041 | 2393 | IrPrint *irp = &ir_print; |
| 2394 | irp->pass_num = pass_num; | |
| 2042 | 2395 | irp->codegen = codegen; |
| 2043 | 2396 | irp->f = f; |
| 2044 | 2397 | irp->indent = indent_size; |
| 2045 | 2398 | irp->indent_size = indent_size; |
| 2399 | irp->printed = {}; | |
| 2400 | irp->printed.init(64); | |
| 2401 | irp->pending = {}; | |
| 2046 | 2402 | |
| 2047 | 2403 | for (size_t bb_i = 0; bb_i < executable->basic_block_list.length; bb_i += 1) { |
| 2048 | 2404 | IrBasicBlock *current_block = executable->basic_block_list.at(bb_i); |
| 2049 | 2405 | fprintf(irp->f, "%s_%" ZIG_PRI_usize ":\n", current_block->name_hint, current_block->debug_id); |
| 2050 | 2406 | for (size_t instr_i = 0; instr_i < current_block->instruction_list.length; instr_i += 1) { |
| 2051 | 2407 | IrInstruction *instruction = current_block->instruction_list.at(instr_i); |
| 2052 | ir_print_instruction(irp, instruction); | |
| 2408 | if (irp->pass_num == 2) { | |
| 2409 | irp->printed.put(instruction, 0); | |
| 2410 | irp->pending.clear(); | |
| 2411 | } | |
| 2412 | ir_print_instruction(irp, instruction, false); | |
| 2413 | for (size_t j = 0; j < irp->pending.length; ++j) | |
| 2414 | ir_print_instruction(irp, irp->pending.at(j), true); | |
| 2053 | 2415 | } |
| 2054 | 2416 | } |
| 2417 | ||
| 2418 | irp->pending.deinit(); | |
| 2419 | irp->printed.deinit(); | |
| 2055 | 2420 | } |
| 2056 | 2421 | |
| 2057 | void ir_print_instruction(CodeGen *codegen, FILE *f, IrInstruction *instruction, int indent_size) { | |
| 2422 | void ir_print_instruction(CodeGen *codegen, FILE *f, IrInstruction *instruction, int indent_size, size_t pass_num) { | |
| 2058 | 2423 | IrPrint ir_print = {}; |
| 2059 | 2424 | IrPrint *irp = &ir_print; |
| 2425 | irp->pass_num = pass_num; | |
| 2060 | 2426 | irp->codegen = codegen; |
| 2061 | 2427 | irp->f = f; |
| 2062 | 2428 | irp->indent = indent_size; |
| 2063 | 2429 | irp->indent_size = indent_size; |
| 2430 | irp->printed = {}; | |
| 2431 | irp->printed.init(4); | |
| 2432 | irp->pending = {}; | |
| 2064 | 2433 | |
| 2065 | ir_print_instruction(irp, instruction); | |
| 2434 | ir_print_instruction(irp, instruction, false); | |
| 2066 | 2435 | } |
src/ir_print.hpp+2-2| ... | ... | @@ -12,7 +12,7 @@ |
| 12 | 12 | |
| 13 | 13 | #include <stdio.h> |
| 14 | 14 | |
| 15 | void ir_print(CodeGen *codegen, FILE *f, IrExecutable *executable, int indent_size); | |
| 16 | void ir_print_instruction(CodeGen *codegen, FILE *f, IrInstruction *instruction, int indent_size); | |
| 15 | void ir_print(CodeGen *codegen, FILE *f, IrExecutable *executable, int indent_size, size_t pass_num); | |
| 16 | void ir_print_instruction(CodeGen *codegen, FILE *f, IrInstruction *instruction, int indent_size, size_t pass_num); | |
| 17 | 17 | |
| 18 | 18 | #endif |
src/os.cpp+15-15| ... | ... | @@ -1125,27 +1125,29 @@ Error os_get_cwd(Buf *out_cwd) { |
| 1125 | 1125 | #endif |
| 1126 | 1126 | } |
| 1127 | 1127 | |
| 1128 | #if defined(ZIG_OS_WINDOWS) | |
| 1128 | 1129 | #define is_wprefix(s, prefix) \ |
| 1129 | 1130 | (wcsncmp((s), (prefix), sizeof(prefix) / sizeof(WCHAR) - 1) == 0) |
| 1130 | bool ATTRIBUTE_MUST_USE os_is_cygwin_pty(int fd) { | |
| 1131 | #if defined(ZIG_OS_WINDOWS) | |
| 1132 | HANDLE handle = (HANDLE)_get_osfhandle(fd); | |
| 1133 | ||
| 1134 | // Cygwin/msys's pty is a pipe. | |
| 1135 | if (handle == INVALID_HANDLE_VALUE || GetFileType(handle) != FILE_TYPE_PIPE) { | |
| 1131 | static bool is_stderr_cyg_pty(void) { | |
| 1132 | HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE); | |
| 1133 | if (stderr_handle == INVALID_HANDLE_VALUE) | |
| 1136 | 1134 | return false; |
| 1137 | } | |
| 1138 | 1135 | |
| 1139 | 1136 | int size = sizeof(FILE_NAME_INFO) + sizeof(WCHAR) * MAX_PATH; |
| 1137 | FILE_NAME_INFO *nameinfo; | |
| 1140 | 1138 | WCHAR *p = NULL; |
| 1141 | 1139 | |
| 1142 | FILE_NAME_INFO *nameinfo = (FILE_NAME_INFO *)allocate<char>(size); | |
| 1140 | // Cygwin/msys's pty is a pipe. | |
| 1141 | if (GetFileType(stderr_handle) != FILE_TYPE_PIPE) { | |
| 1142 | return 0; | |
| 1143 | } | |
| 1144 | nameinfo = (FILE_NAME_INFO *)allocate<char>(size); | |
| 1143 | 1145 | if (nameinfo == NULL) { |
| 1144 | return false; | |
| 1146 | return 0; | |
| 1145 | 1147 | } |
| 1146 | 1148 | // Check the name of the pipe: |
| 1147 | 1149 | // '\{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master' |
| 1148 | if (GetFileInformationByHandleEx(handle, FileNameInfo, nameinfo, size)) { | |
| 1150 | if (GetFileInformationByHandleEx(stderr_handle, FileNameInfo, nameinfo, size)) { | |
| 1149 | 1151 | nameinfo->FileName[nameinfo->FileNameLength / sizeof(WCHAR)] = L'\0'; |
| 1150 | 1152 | p = nameinfo->FileName; |
| 1151 | 1153 | if (is_wprefix(p, L"\\cygwin-")) { /* Cygwin */ |
| ... | ... | @@ -1178,14 +1180,12 @@ bool ATTRIBUTE_MUST_USE os_is_cygwin_pty(int fd) { |
| 1178 | 1180 | } |
| 1179 | 1181 | free(nameinfo); |
| 1180 | 1182 | return (p != NULL); |
| 1181 | #else | |
| 1182 | return false; | |
| 1183 | #endif | |
| 1184 | 1183 | } |
| 1184 | #endif | |
| 1185 | 1185 | |
| 1186 | 1186 | bool os_stderr_tty(void) { |
| 1187 | 1187 | #if defined(ZIG_OS_WINDOWS) |
| 1188 | return _isatty(fileno(stderr)) != 0 || os_is_cygwin_pty(fileno(stderr)); | |
| 1188 | return _isatty(_fileno(stderr)) != 0 || is_stderr_cyg_pty(); | |
| 1189 | 1189 | #elif defined(ZIG_OS_POSIX) |
| 1190 | 1190 | return isatty(STDERR_FILENO) != 0; |
| 1191 | 1191 | #else |
| ... | ... | @@ -1486,7 +1486,7 @@ WORD original_console_attributes = FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BL |
| 1486 | 1486 | |
| 1487 | 1487 | void os_stderr_set_color(TermColor color) { |
| 1488 | 1488 | #if defined(ZIG_OS_WINDOWS) |
| 1489 | if (os_stderr_tty()) { | |
| 1489 | if (is_stderr_cyg_pty()) { | |
| 1490 | 1490 | set_color_posix(color); |
| 1491 | 1491 | return; |
| 1492 | 1492 | } |
src/os.hpp-8| ... | ... | @@ -11,7 +11,6 @@ |
| 11 | 11 | #include "list.hpp" |
| 12 | 12 | #include "buffer.hpp" |
| 13 | 13 | #include "error.hpp" |
| 14 | #include "target.hpp" | |
| 15 | 14 | #include "zig_llvm.h" |
| 16 | 15 | #include "windows_sdk.h" |
| 17 | 16 | |
| ... | ... | @@ -89,11 +88,6 @@ struct Termination { |
| 89 | 88 | #define OsFile int |
| 90 | 89 | #endif |
| 91 | 90 | |
| 92 | #if defined(ZIG_OS_WINDOWS) | |
| 93 | #undef fileno | |
| 94 | #define fileno _fileno | |
| 95 | #endif | |
| 96 | ||
| 97 | 91 | struct OsTimeStamp { |
| 98 | 92 | uint64_t sec; |
| 99 | 93 | uint64_t nsec; |
| ... | ... | @@ -158,8 +152,6 @@ Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf |
| 158 | 152 | Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type); |
| 159 | 153 | Error ATTRIBUTE_MUST_USE os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type); |
| 160 | 154 | |
| 161 | bool ATTRIBUTE_MUST_USE os_is_cygwin_pty(int fd); | |
| 162 | ||
| 163 | 155 | Error ATTRIBUTE_MUST_USE os_self_exe_shared_libs(ZigList<Buf *> &paths); |
| 164 | 156 | |
| 165 | 157 | #endif |
src/parser.cpp+1-1| ... | ... | @@ -2075,7 +2075,7 @@ static AstNode *ast_parse_param_decl(ParseContext *pc) { |
| 2075 | 2075 | res->column = first->start_column; |
| 2076 | 2076 | res->data.param_decl.name = token_buf(name); |
| 2077 | 2077 | res->data.param_decl.is_noalias = first->id == TokenIdKeywordNoAlias; |
| 2078 | res->data.param_decl.is_inline = first->id == TokenIdKeywordCompTime; | |
| 2078 | res->data.param_decl.is_comptime = first->id == TokenIdKeywordCompTime; | |
| 2079 | 2079 | return res; |
| 2080 | 2080 | } |
| 2081 | 2081 |
src/target.cpp+1-14| ... | ... | @@ -491,16 +491,6 @@ Error target_parse_glibc_version(ZigGLibCVersion *glibc_ver, const char *text) { |
| 491 | 491 | return ErrorNone; |
| 492 | 492 | } |
| 493 | 493 | |
| 494 | static ZigLLVM_EnvironmentType target_get_win32_abi() { | |
| 495 | FILE* files[] = { stdin, stdout, stderr, nullptr }; | |
| 496 | for (int i = 0; files[i] != nullptr; i++) { | |
| 497 | if (os_is_cygwin_pty(fileno(files[i]))) { | |
| 498 | return ZigLLVM_GNU; | |
| 499 | } | |
| 500 | } | |
| 501 | return ZigLLVM_MSVC; | |
| 502 | } | |
| 503 | ||
| 504 | 494 | void get_native_target(ZigTarget *target) { |
| 505 | 495 | // first zero initialize |
| 506 | 496 | *target = {}; |
| ... | ... | @@ -515,9 +505,6 @@ void get_native_target(ZigTarget *target) { |
| 515 | 505 | &target->abi, |
| 516 | 506 | &oformat); |
| 517 | 507 | target->os = get_zig_os_type(os_type); |
| 518 | if (target->os == OsWindows) { | |
| 519 | target->abi = target_get_win32_abi(); | |
| 520 | } | |
| 521 | 508 | target->is_native = true; |
| 522 | 509 | if (target->abi == ZigLLVM_UnknownEnvironment) { |
| 523 | 510 | target->abi = target_default_abi(target->arch, target->os); |
| ... | ... | @@ -1614,7 +1601,7 @@ ZigLLVM_EnvironmentType target_default_abi(ZigLLVM_ArchType arch, Os os) { |
| 1614 | 1601 | return ZigLLVM_GNU; |
| 1615 | 1602 | case OsUefi: |
| 1616 | 1603 | case OsWindows: |
| 1617 | return ZigLLVM_MSVC; | |
| 1604 | return ZigLLVM_MSVC; | |
| 1618 | 1605 | case OsLinux: |
| 1619 | 1606 | case OsWASI: |
| 1620 | 1607 | return ZigLLVM_Musl; |
std/mem.zig+9-1| ... | ... | @@ -117,7 +117,15 @@ pub const Allocator = struct { |
| 117 | 117 | const byte_slice = try self.reallocFn(self, ([*]u8)(undefined)[0..0], undefined, byte_count, a); |
| 118 | 118 | assert(byte_slice.len == byte_count); |
| 119 | 119 | @memset(byte_slice.ptr, undefined, byte_slice.len); |
| 120 | return @bytesToSlice(T, @alignCast(a, byte_slice)); | |
| 120 | if (alignment == null) { | |
| 121 | // TODO This is a workaround for zig not being able to successfully do | |
| 122 | // @bytesToSlice(T, @alignCast(a, byte_slice)) without resolving alignment of T, | |
| 123 | // which causes a circular dependency in async functions which try to heap-allocate | |
| 124 | // their own frame with @Frame(func). | |
| 125 | return @intToPtr([*]T, @ptrToInt(byte_slice.ptr))[0..n]; | |
| 126 | } else { | |
| 127 | return @bytesToSlice(T, @alignCast(a, byte_slice)); | |
| 128 | } | |
| 121 | 129 | } |
| 122 | 130 | |
| 123 | 131 | /// This function requests a new byte size for an existing allocation, |
std/os/windows.zig+4-3| ... | ... | @@ -65,7 +65,7 @@ pub const CreateFileError = error{ |
| 65 | 65 | InvalidUtf8, |
| 66 | 66 | |
| 67 | 67 | /// On Windows, file paths cannot contain these characters: |
| 68 | /// '*', '?', '"', '<', '>', '|', and '/' (when the ABI is not GNU) | |
| 68 | /// '/', '*', '?', '"', '<', '>', '|' | |
| 69 | 69 | BadPathName, |
| 70 | 70 | |
| 71 | 71 | Unexpected, |
| ... | ... | @@ -836,10 +836,11 @@ pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) |
| 836 | 836 | // > converting the name to an NT-style name, except when using the "\\?\" |
| 837 | 837 | // > prefix as detailed in the following sections. |
| 838 | 838 | // from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation |
| 839 | // Because we want the larger maximum path length for absolute paths, we | |
| 840 | // disallow forward slashes in zig std lib file functions on Windows. | |
| 839 | 841 | for (s) |byte| { |
| 840 | 842 | switch (byte) { |
| 841 | '*', '?', '"', '<', '>', '|' => return error.BadPathName, | |
| 842 | '/' => if (builtin.abi == .msvc) return error.BadPathName, | |
| 843 | '/', '*', '?', '"', '<', '>', '|' => return error.BadPathName, | |
| 843 | 844 | else => {}, |
| 844 | 845 | } |
| 845 | 846 | } |
std/special/compiler_rt/comparetf2.zig+7-6| ... | ... | @@ -38,12 +38,14 @@ pub extern fn __letf2(a: f128, b: f128) c_int { |
| 38 | 38 | |
| 39 | 39 | // If at least one of a and b is positive, we get the same result comparing |
| 40 | 40 | // a and b as signed integers as we would with a floating-point compare. |
| 41 | return if ((aInt & bInt) >= 0) if (aInt < bInt) | |
| 42 | LE_LESS | |
| 43 | else if (aInt == bInt) | |
| 44 | LE_EQUAL | |
| 41 | return if ((aInt & bInt) >= 0) | |
| 42 | if (aInt < bInt) | |
| 43 | LE_LESS | |
| 44 | else if (aInt == bInt) | |
| 45 | LE_EQUAL | |
| 46 | else | |
| 47 | LE_GREATER | |
| 45 | 48 | else |
| 46 | LE_GREATER else | |
| 47 | 49 | // Otherwise, both are negative, so we need to flip the sense of the |
| 48 | 50 | // comparison to get the correct result. (This assumes a twos- or ones- |
| 49 | 51 | // complement integer representation; if integers are represented in a |
| ... | ... | @@ -73,7 +75,6 @@ pub extern fn __getf2(a: f128, b: f128) c_int { |
| 73 | 75 | |
| 74 | 76 | if (aAbs > infRep or bAbs > infRep) return GE_UNORDERED; |
| 75 | 77 | if ((aAbs | bAbs) == 0) return GE_EQUAL; |
| 76 | // zig fmt issue here, see https://github.com/ziglang/zig/issues/2661 | |
| 77 | 78 | return if ((aInt & bInt) >= 0) |
| 78 | 79 | if (aInt < bInt) |
| 79 | 80 | GE_LESS |
std/zig/parser_test.zig+21| ... | ... | @@ -482,6 +482,27 @@ test "zig fmt: if-else with comment before else" { |
| 482 | 482 | ); |
| 483 | 483 | } |
| 484 | 484 | |
| 485 | test "zig fmt: if nested" { | |
| 486 | try testCanonical( | |
| 487 | \\pub fn foo() void { | |
| 488 | \\ return if ((aInt & bInt) >= 0) | |
| 489 | \\ if (aInt < bInt) | |
| 490 | \\ GE_LESS | |
| 491 | \\ else if (aInt == bInt) | |
| 492 | \\ GE_EQUAL | |
| 493 | \\ else | |
| 494 | \\ GE_GREATER | |
| 495 | \\ else if (aInt > bInt) | |
| 496 | \\ GE_LESS | |
| 497 | \\ else if (aInt == bInt) | |
| 498 | \\ GE_EQUAL | |
| 499 | \\ else | |
| 500 | \\ GE_GREATER; | |
| 501 | \\} | |
| 502 | \\ | |
| 503 | ); | |
| 504 | } | |
| 505 | ||
| 485 | 506 | test "zig fmt: respect line breaks in if-else" { |
| 486 | 507 | try testCanonical( |
| 487 | 508 | \\comptime { |
std/zig/render.zig+4-2| ... | ... | @@ -276,7 +276,6 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, i |
| 276 | 276 | } else { |
| 277 | 277 | try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, Space.Comma); // type, |
| 278 | 278 | } |
| 279 | ||
| 280 | 279 | } else if (field.type_expr == null and field.value_expr != null) { |
| 281 | 280 | try renderToken(tree, stream, field.name_token, indent, start_col, Space.Space); // name |
| 282 | 281 | try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, Space.Space); // = |
| ... | ... | @@ -1521,9 +1520,12 @@ fn renderExpression( |
| 1521 | 1520 | |
| 1522 | 1521 | try renderExpression(allocator, stream, tree, indent, start_col, if_node.condition, Space.None); // condition |
| 1523 | 1522 | |
| 1523 | const body_is_if_block = if_node.body.id == ast.Node.Id.If; | |
| 1524 | 1524 | const body_is_block = nodeIsBlock(if_node.body); |
| 1525 | 1525 | |
| 1526 | if (body_is_block) { | |
| 1526 | if (body_is_if_block) { | |
| 1527 | try renderExtraNewline(tree, stream, start_col, if_node.body); | |
| 1528 | } else if (body_is_block) { | |
| 1527 | 1529 | const after_rparen_space = if (if_node.payload == null) Space.BlockStart else Space.Space; |
| 1528 | 1530 | try renderToken(tree, stream, rparen, indent, start_col, after_rparen_space); // ) |
| 1529 | 1531 |
test/compile_errors.zig+18| ... | ... | @@ -2,6 +2,22 @@ const tests = @import("tests.zig"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | 3 | |
| 4 | 4 | pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5 | cases.add( | |
| 6 | "wrong type for result ptr to @asyncCall", | |
| 7 | \\export fn entry() void { | |
| 8 | \\ _ = async amain(); | |
| 9 | \\} | |
| 10 | \\fn amain() i32 { | |
| 11 | \\ var frame: @Frame(foo) = undefined; | |
| 12 | \\ return await @asyncCall(&frame, false, foo); | |
| 13 | \\} | |
| 14 | \\fn foo() i32 { | |
| 15 | \\ return 1234; | |
| 16 | \\} | |
| 17 | , | |
| 18 | "tmp.zig:6:37: error: expected type '*i32', found 'bool'", | |
| 19 | ); | |
| 20 | ||
| 5 | 21 | cases.add( |
| 6 | 22 | "struct depends on itself via optional field", |
| 7 | 23 | \\const LhsExpr = struct { |
| ... | ... | @@ -1051,6 +1067,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1051 | 1067 | \\const Foo = struct {}; |
| 1052 | 1068 | \\export fn a() void { |
| 1053 | 1069 | \\ const T = [*c]Foo; |
| 1070 | \\ var t: T = undefined; | |
| 1054 | 1071 | \\} |
| 1055 | 1072 | , |
| 1056 | 1073 | "tmp.zig:3:19: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'", |
| ... | ... | @@ -2290,6 +2307,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 2290 | 2307 | "error union operator with non error set LHS", |
| 2291 | 2308 | \\comptime { |
| 2292 | 2309 | \\ const z = i32!i32; |
| 2310 | \\ var x: z = undefined; | |
| 2293 | 2311 | \\} |
| 2294 | 2312 | , |
| 2295 | 2313 | "tmp.zig:2:15: error: expected error set type, found type 'i32'", |
test/stage1/behavior/async_fn.zig+179-2| ... | ... | @@ -331,8 +331,9 @@ test "async fn with inferred error set" { |
| 331 | 331 | |
| 332 | 332 | fn doTheTest() void { |
| 333 | 333 | var frame: [1]@Frame(middle) = undefined; |
| 334 | var result: anyerror!void = undefined; | |
| 335 | _ = @asyncCall(@sliceToBytes(frame[0..]), &result, middle); | |
| 334 | var fn_ptr = middle; | |
| 335 | var result: @typeOf(fn_ptr).ReturnType.ErrorSet!void = undefined; | |
| 336 | _ = @asyncCall(@sliceToBytes(frame[0..]), &result, fn_ptr); | |
| 336 | 337 | resume global_frame; |
| 337 | 338 | std.testing.expectError(error.Fail, result); |
| 338 | 339 | } |
| ... | ... | @@ -819,6 +820,34 @@ test "struct parameter to async function is copied to the frame" { |
| 819 | 820 | } |
| 820 | 821 | |
| 821 | 822 | test "cast fn to async fn when it is inferred to be async" { |
| 823 | const S = struct { | |
| 824 | var frame: anyframe = undefined; | |
| 825 | var ok = false; | |
| 826 | ||
| 827 | fn doTheTest() void { | |
| 828 | var ptr: async fn () i32 = undefined; | |
| 829 | ptr = func; | |
| 830 | var buf: [100]u8 align(16) = undefined; | |
| 831 | var result: i32 = undefined; | |
| 832 | const f = @asyncCall(&buf, &result, ptr); | |
| 833 | _ = await f; | |
| 834 | expect(result == 1234); | |
| 835 | ok = true; | |
| 836 | } | |
| 837 | ||
| 838 | fn func() i32 { | |
| 839 | suspend { | |
| 840 | frame = @frame(); | |
| 841 | } | |
| 842 | return 1234; | |
| 843 | } | |
| 844 | }; | |
| 845 | _ = async S.doTheTest(); | |
| 846 | resume S.frame; | |
| 847 | expect(S.ok); | |
| 848 | } | |
| 849 | ||
| 850 | test "cast fn to async fn when it is inferred to be async, awaited directly" { | |
| 822 | 851 | const S = struct { |
| 823 | 852 | var frame: anyframe = undefined; |
| 824 | 853 | var ok = false; |
| ... | ... | @@ -854,3 +883,151 @@ test "await does not force async if callee is blocking" { |
| 854 | 883 | var x = async S.simple(); |
| 855 | 884 | expect(await x == 1234); |
| 856 | 885 | } |
| 886 | ||
| 887 | test "recursive async function" { | |
| 888 | expect(recursiveAsyncFunctionTest(false).doTheTest() == 55); | |
| 889 | expect(recursiveAsyncFunctionTest(true).doTheTest() == 55); | |
| 890 | } | |
| 891 | ||
| 892 | fn recursiveAsyncFunctionTest(comptime suspending_implementation: bool) type { | |
| 893 | return struct { | |
| 894 | fn fib(allocator: *std.mem.Allocator, x: u32) error{OutOfMemory}!u32 { | |
| 895 | if (x <= 1) return x; | |
| 896 | ||
| 897 | if (suspending_implementation) { | |
| 898 | suspend { | |
| 899 | resume @frame(); | |
| 900 | } | |
| 901 | } | |
| 902 | ||
| 903 | const f1 = try allocator.create(@Frame(fib)); | |
| 904 | defer allocator.destroy(f1); | |
| 905 | ||
| 906 | const f2 = try allocator.create(@Frame(fib)); | |
| 907 | defer allocator.destroy(f2); | |
| 908 | ||
| 909 | f1.* = async fib(allocator, x - 1); | |
| 910 | var f1_awaited = false; | |
| 911 | errdefer if (!f1_awaited) { | |
| 912 | _ = await f1; | |
| 913 | }; | |
| 914 | ||
| 915 | f2.* = async fib(allocator, x - 2); | |
| 916 | var f2_awaited = false; | |
| 917 | errdefer if (!f2_awaited) { | |
| 918 | _ = await f2; | |
| 919 | }; | |
| 920 | ||
| 921 | var sum: u32 = 0; | |
| 922 | ||
| 923 | f1_awaited = true; | |
| 924 | const result_f1 = await f1; // TODO https://github.com/ziglang/zig/issues/3077 | |
| 925 | sum += try result_f1; | |
| 926 | ||
| 927 | f2_awaited = true; | |
| 928 | const result_f2 = await f2; // TODO https://github.com/ziglang/zig/issues/3077 | |
| 929 | sum += try result_f2; | |
| 930 | ||
| 931 | return sum; | |
| 932 | } | |
| 933 | ||
| 934 | fn doTheTest() u32 { | |
| 935 | if (suspending_implementation) { | |
| 936 | var result: u32 = undefined; | |
| 937 | _ = async amain(&result); | |
| 938 | return result; | |
| 939 | } else { | |
| 940 | return fib(std.heap.direct_allocator, 10) catch unreachable; | |
| 941 | } | |
| 942 | } | |
| 943 | ||
| 944 | fn amain(result: *u32) void { | |
| 945 | var x = async fib(std.heap.direct_allocator, 10); | |
| 946 | const res = await x; // TODO https://github.com/ziglang/zig/issues/3077 | |
| 947 | result.* = res catch unreachable; | |
| 948 | } | |
| 949 | }; | |
| 950 | } | |
| 951 | ||
| 952 | test "@asyncCall with comptime-known function, but not awaited directly" { | |
| 953 | const S = struct { | |
| 954 | var global_frame: anyframe = undefined; | |
| 955 | ||
| 956 | fn doTheTest() void { | |
| 957 | var frame: [1]@Frame(middle) = undefined; | |
| 958 | var result: @typeOf(middle).ReturnType.ErrorSet!void = undefined; | |
| 959 | _ = @asyncCall(@sliceToBytes(frame[0..]), &result, middle); | |
| 960 | resume global_frame; | |
| 961 | std.testing.expectError(error.Fail, result); | |
| 962 | } | |
| 963 | ||
| 964 | async fn middle() !void { | |
| 965 | var f = async middle2(); | |
| 966 | return await f; | |
| 967 | } | |
| 968 | ||
| 969 | fn middle2() !void { | |
| 970 | return failing(); | |
| 971 | } | |
| 972 | ||
| 973 | fn failing() !void { | |
| 974 | global_frame = @frame(); | |
| 975 | suspend; | |
| 976 | return error.Fail; | |
| 977 | } | |
| 978 | }; | |
| 979 | S.doTheTest(); | |
| 980 | } | |
| 981 | ||
| 982 | test "@asyncCall with actual frame instead of byte buffer" { | |
| 983 | const S = struct { | |
| 984 | fn func() i32 { | |
| 985 | suspend; | |
| 986 | return 1234; | |
| 987 | } | |
| 988 | }; | |
| 989 | var frame: @Frame(S.func) = undefined; | |
| 990 | var result: i32 = undefined; | |
| 991 | const ptr = @asyncCall(&frame, &result, S.func); | |
| 992 | resume ptr; | |
| 993 | expect(result == 1234); | |
| 994 | } | |
| 995 | ||
| 996 | test "@asyncCall using the result location inside the frame" { | |
| 997 | const S = struct { | |
| 998 | async fn simple2(y: *i32) i32 { | |
| 999 | defer y.* += 2; | |
| 1000 | y.* += 1; | |
| 1001 | suspend; | |
| 1002 | return 1234; | |
| 1003 | } | |
| 1004 | fn getAnswer(f: anyframe->i32, out: *i32) void { | |
| 1005 | var res = await f; // TODO https://github.com/ziglang/zig/issues/3077 | |
| 1006 | out.* = res; | |
| 1007 | } | |
| 1008 | }; | |
| 1009 | var data: i32 = 1; | |
| 1010 | const Foo = struct { | |
| 1011 | bar: async fn (*i32) i32, | |
| 1012 | }; | |
| 1013 | var foo = Foo{ .bar = S.simple2 }; | |
| 1014 | var bytes: [64]u8 align(16) = undefined; | |
| 1015 | const f = @asyncCall(&bytes, {}, foo.bar, &data); | |
| 1016 | comptime expect(@typeOf(f) == anyframe->i32); | |
| 1017 | expect(data == 2); | |
| 1018 | resume f; | |
| 1019 | expect(data == 4); | |
| 1020 | _ = async S.getAnswer(f, &data); | |
| 1021 | expect(data == 1234); | |
| 1022 | } | |
| 1023 | ||
| 1024 | test "@typeOf an async function call of generic fn with error union type" { | |
| 1025 | const S = struct { | |
| 1026 | fn func(comptime x: var) anyerror!i32 { | |
| 1027 | const T = @typeOf(async func(x)); | |
| 1028 | comptime expect(T == @typeOf(@frame()).Child); | |
| 1029 | return undefined; | |
| 1030 | } | |
| 1031 | }; | |
| 1032 | _ = async S.func(i32); | |
| 1033 | } |
test/stage1/behavior/sizeof_and_typeof.zig+26| ... | ... | @@ -89,3 +89,29 @@ test "@sizeOf(T) == 0 doesn't force resolving struct size" { |
| 89 | 89 | expect(@sizeOf(S.Foo) == 4); |
| 90 | 90 | expect(@sizeOf(S.Bar) == 8); |
| 91 | 91 | } |
| 92 | ||
| 93 | test "@typeOf() has no runtime side effects" { | |
| 94 | const S = struct { | |
| 95 | fn foo(comptime T: type, ptr: *T) T { | |
| 96 | ptr.* += 1; | |
| 97 | return ptr.*; | |
| 98 | } | |
| 99 | }; | |
| 100 | var data: i32 = 0; | |
| 101 | const T = @typeOf(S.foo(i32, &data)); | |
| 102 | comptime expect(T == i32); | |
| 103 | expect(data == 0); | |
| 104 | } | |
| 105 | ||
| 106 | test "branching logic inside @typeOf" { | |
| 107 | const S = struct { | |
| 108 | var data: i32 = 0; | |
| 109 | fn foo() anyerror!i32 { | |
| 110 | data += 1; | |
| 111 | return undefined; | |
| 112 | } | |
| 113 | }; | |
| 114 | const T = @typeOf(S.foo() catch undefined); | |
| 115 | comptime expect(T == i32); | |
| 116 | expect(S.data == 0); | |
| 117 | } |