| author | |
| committer | |
| log | fef06f2142a0f7ec65d3500aff509c74d89bf63b |
| tree | 151da8064d7f08e1f56b13c4a2ef73d2148aa450 |
| parent | 7186e92c86982950d0aa7c0c2deef9ef96bc1264 |
| parent | ee1a4f4c1d888d1485d8bb13ee0fa756bf729b08 |
closes #8216 files changed, 538 insertions(+), 123 deletions(-)
src/all_types.hpp+32-1| ... | @@ -1656,6 +1656,8 @@ struct CodeGen { | ... | @@ -1656,6 +1656,8 @@ struct CodeGen { |
| 1656 | LLVMValueRef coro_save_fn_val; | 1656 | LLVMValueRef coro_save_fn_val; |
| 1657 | LLVMValueRef coro_promise_fn_val; | 1657 | LLVMValueRef coro_promise_fn_val; |
| 1658 | LLVMValueRef coro_alloc_helper_fn_val; | 1658 | LLVMValueRef coro_alloc_helper_fn_val; |
| 1659 | LLVMValueRef merge_err_ret_traces_fn_val; | ||
| 1660 | LLVMValueRef add_error_return_trace_addr_fn_val; | ||
| 1659 | bool error_during_imports; | 1661 | bool error_during_imports; |
| 1660 | 1662 | ||
| 1661 | const char **clang_argv; | 1663 | const char **clang_argv; |
| ... | @@ -2054,6 +2056,8 @@ enum IrInstructionId { | ... | @@ -2054,6 +2056,8 @@ enum IrInstructionId { |
| 2054 | IrInstructionIdAwaitBookkeeping, | 2056 | IrInstructionIdAwaitBookkeeping, |
| 2055 | IrInstructionIdSaveErrRetAddr, | 2057 | IrInstructionIdSaveErrRetAddr, |
| 2056 | IrInstructionIdAddImplicitReturnType, | 2058 | IrInstructionIdAddImplicitReturnType, |
| 2059 | IrInstructionIdMergeErrRetTraces, | ||
| 2060 | IrInstructionIdMarkErrRetTracePtr, | ||
| 2057 | }; | 2061 | }; |
| 2058 | 2062 | ||
| 2059 | struct IrInstruction { | 2063 | struct IrInstruction { |
| ... | @@ -2892,6 +2896,11 @@ struct IrInstructionExport { | ... | @@ -2892,6 +2896,11 @@ struct IrInstructionExport { |
| 2892 | 2896 | ||
| 2893 | struct IrInstructionErrorReturnTrace { | 2897 | struct IrInstructionErrorReturnTrace { |
| 2894 | IrInstruction base; | 2898 | IrInstruction base; |
| 2899 | |||
| 2900 | enum Nullable { | ||
| 2901 | Null, | ||
| 2902 | NonNull, | ||
| 2903 | } nullable; | ||
| 2895 | }; | 2904 | }; |
| 2896 | 2905 | ||
| 2897 | struct IrInstructionErrorUnion { | 2906 | struct IrInstructionErrorUnion { |
| ... | @@ -3024,6 +3033,20 @@ struct IrInstructionAddImplicitReturnType { | ... | @@ -3024,6 +3033,20 @@ struct IrInstructionAddImplicitReturnType { |
| 3024 | IrInstruction *value; | 3033 | IrInstruction *value; |
| 3025 | }; | 3034 | }; |
| 3026 | 3035 | ||
| 3036 | struct IrInstructionMergeErrRetTraces { | ||
| 3037 | IrInstruction base; | ||
| 3038 | |||
| 3039 | IrInstruction *coro_promise_ptr; | ||
| 3040 | IrInstruction *src_err_ret_trace_ptr; | ||
| 3041 | IrInstruction *dest_err_ret_trace_ptr; | ||
| 3042 | }; | ||
| 3043 | |||
| 3044 | struct IrInstructionMarkErrRetTracePtr { | ||
| 3045 | IrInstruction base; | ||
| 3046 | |||
| 3047 | IrInstruction *err_ret_trace_ptr; | ||
| 3048 | }; | ||
| 3049 | |||
| 3027 | static const size_t slice_ptr_index = 0; | 3050 | static const size_t slice_ptr_index = 0; |
| 3028 | static const size_t slice_len_index = 1; | 3051 | static const size_t slice_len_index = 1; |
| 3029 | 3052 | ||
| ... | @@ -3033,10 +3056,18 @@ static const size_t maybe_null_index = 1; | ... | @@ -3033,10 +3056,18 @@ static const size_t maybe_null_index = 1; |
| 3033 | static const size_t err_union_err_index = 0; | 3056 | static const size_t err_union_err_index = 0; |
| 3034 | static const size_t err_union_payload_index = 1; | 3057 | static const size_t err_union_payload_index = 1; |
| 3035 | 3058 | ||
| 3059 | // TODO call graph analysis to find out what this number needs to be for every function | ||
| 3060 | static const size_t stack_trace_ptr_count = 30; | ||
| 3061 | |||
| 3062 | // these belong to the async function | ||
| 3063 | #define RETURN_ADDRESSES_FIELD_NAME "return_addresses" | ||
| 3064 | #define ERR_RET_TRACE_FIELD_NAME "err_ret_trace" | ||
| 3065 | #define RESULT_FIELD_NAME "result" | ||
| 3036 | #define ASYNC_ALLOC_FIELD_NAME "allocFn" | 3066 | #define ASYNC_ALLOC_FIELD_NAME "allocFn" |
| 3037 | #define ASYNC_FREE_FIELD_NAME "freeFn" | 3067 | #define ASYNC_FREE_FIELD_NAME "freeFn" |
| 3038 | #define AWAITER_HANDLE_FIELD_NAME "awaiter_handle" | 3068 | #define AWAITER_HANDLE_FIELD_NAME "awaiter_handle" |
| 3039 | #define RESULT_FIELD_NAME "result" | 3069 | // these point to data belonging to the awaiter |
| 3070 | #define ERR_RET_TRACE_PTR_FIELD_NAME "err_ret_trace_ptr" | ||
| 3040 | #define RESULT_PTR_FIELD_NAME "result_ptr" | 3071 | #define RESULT_PTR_FIELD_NAME "result_ptr" |
| 3041 | 3072 | ||
| 3042 | 3073 |
src/analyze.cpp+23-3| ... | @@ -468,10 +468,30 @@ TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type) | ... | @@ -468,10 +468,30 @@ TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type) |
| 468 | 468 | ||
| 469 | TypeTableEntry *awaiter_handle_type = get_maybe_type(g, g->builtin_types.entry_promise); | 469 | TypeTableEntry *awaiter_handle_type = get_maybe_type(g, g->builtin_types.entry_promise); |
| 470 | TypeTableEntry *result_ptr_type = get_pointer_to_type(g, return_type, false); | 470 | TypeTableEntry *result_ptr_type = get_pointer_to_type(g, return_type, false); |
| 471 | const char *field_names[] = {AWAITER_HANDLE_FIELD_NAME, RESULT_FIELD_NAME, RESULT_PTR_FIELD_NAME}; | 471 | |
| 472 | TypeTableEntry *field_types[] = {awaiter_handle_type, return_type, result_ptr_type}; | 472 | ZigList<const char *> field_names = {}; |
| 473 | field_names.append(AWAITER_HANDLE_FIELD_NAME); | ||
| 474 | field_names.append(RESULT_FIELD_NAME); | ||
| 475 | field_names.append(RESULT_PTR_FIELD_NAME); | ||
| 476 | if (g->have_err_ret_tracing) { | ||
| 477 | field_names.append(ERR_RET_TRACE_PTR_FIELD_NAME); | ||
| 478 | field_names.append(ERR_RET_TRACE_FIELD_NAME); | ||
| 479 | field_names.append(RETURN_ADDRESSES_FIELD_NAME); | ||
| 480 | } | ||
| 481 | |||
| 482 | ZigList<TypeTableEntry *> field_types = {}; | ||
| 483 | field_types.append(awaiter_handle_type); | ||
| 484 | field_types.append(return_type); | ||
| 485 | field_types.append(result_ptr_type); | ||
| 486 | if (g->have_err_ret_tracing) { | ||
| 487 | field_types.append(get_ptr_to_stack_trace_type(g)); | ||
| 488 | field_types.append(g->stack_trace_type); | ||
| 489 | field_types.append(get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count)); | ||
| 490 | } | ||
| 491 | |||
| 492 | assert(field_names.length == field_types.length); | ||
| 473 | Buf *name = buf_sprintf("AsyncFramePromise(%s)", buf_ptr(&return_type->name)); | 493 | Buf *name = buf_sprintf("AsyncFramePromise(%s)", buf_ptr(&return_type->name)); |
| 474 | TypeTableEntry *entry = get_struct_type(g, buf_ptr(name), field_names, field_types, 3); | 494 | TypeTableEntry *entry = get_struct_type(g, buf_ptr(name), field_names.items, field_types.items, field_names.length); |
| 475 | 495 | ||
| 476 | return_type->promise_frame_parent = entry; | 496 | return_type->promise_frame_parent = entry; |
| 477 | return entry; | 497 | return entry; |
src/codegen.cpp+248-46| ... | @@ -1114,22 +1114,19 @@ static LLVMValueRef get_return_address_fn_val(CodeGen *g) { | ... | @@ -1114,22 +1114,19 @@ static LLVMValueRef get_return_address_fn_val(CodeGen *g) { |
| 1114 | return g->return_address_fn_val; | 1114 | return g->return_address_fn_val; |
| 1115 | } | 1115 | } |
| 1116 | 1116 | ||
| 1117 | static LLVMValueRef get_return_err_fn(CodeGen *g) { | 1117 | static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) { |
| 1118 | if (g->return_err_fn != nullptr) | 1118 | if (g->add_error_return_trace_addr_fn_val != nullptr) |
| 1119 | return g->return_err_fn; | 1119 | return g->add_error_return_trace_addr_fn_val; |
| 1120 | |||
| 1121 | assert(g->err_tag_type != nullptr); | ||
| 1122 | 1120 | ||
| 1123 | LLVMTypeRef arg_types[] = { | 1121 | LLVMTypeRef arg_types[] = { |
| 1124 | // error return trace pointer | ||
| 1125 | get_ptr_to_stack_trace_type(g)->type_ref, | 1122 | get_ptr_to_stack_trace_type(g)->type_ref, |
| 1123 | g->builtin_types.entry_usize->type_ref, | ||
| 1126 | }; | 1124 | }; |
| 1127 | LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false); | 1125 | LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false); |
| 1128 | 1126 | ||
| 1129 | Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_return_error"), false); | 1127 | Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_add_err_ret_trace_addr"), false); |
| 1130 | LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref); | 1128 | LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref); |
| 1131 | addLLVMFnAttr(fn_val, "noinline"); // so that we can look at return address | 1129 | addLLVMFnAttr(fn_val, "alwaysinline"); |
| 1132 | addLLVMFnAttr(fn_val, "cold"); | ||
| 1133 | LLVMSetLinkage(fn_val, LLVMInternalLinkage); | 1130 | LLVMSetLinkage(fn_val, LLVMInternalLinkage); |
| 1134 | LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); | 1131 | LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); |
| 1135 | addLLVMFnAttr(fn_val, "nounwind"); | 1132 | addLLVMFnAttr(fn_val, "nounwind"); |
| ... | @@ -1151,6 +1148,8 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) { | ... | @@ -1151,6 +1148,8 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) { |
| 1151 | // stack_trace.instruction_addresses[stack_trace.index % stack_trace.instruction_addresses.len] = return_address; | 1148 | // stack_trace.instruction_addresses[stack_trace.index % stack_trace.instruction_addresses.len] = return_address; |
| 1152 | 1149 | ||
| 1153 | LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0); | 1150 | LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0); |
| 1151 | LLVMValueRef address_value = LLVMGetParam(fn_val, 1); | ||
| 1152 | |||
| 1154 | size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index; | 1153 | size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index; |
| 1155 | LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, err_ret_trace_ptr, (unsigned)index_field_index, ""); | 1154 | LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, err_ret_trace_ptr, (unsigned)index_field_index, ""); |
| 1156 | size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index; | 1155 | size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index; |
| ... | @@ -1172,15 +1171,10 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) { | ... | @@ -1172,15 +1171,10 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) { |
| 1172 | LLVMValueRef ptr_value = gen_load_untyped(g, ptr_field_ptr, 0, false, ""); | 1171 | LLVMValueRef ptr_value = gen_load_untyped(g, ptr_field_ptr, 0, false, ""); |
| 1173 | LLVMValueRef address_slot = LLVMBuildInBoundsGEP(g->builder, ptr_value, address_indices, 1, ""); | 1172 | LLVMValueRef address_slot = LLVMBuildInBoundsGEP(g->builder, ptr_value, address_indices, 1, ""); |
| 1174 | 1173 | ||
| 1175 | LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref); | ||
| 1176 | LLVMValueRef return_address_ptr = LLVMBuildCall(g->builder, get_return_address_fn_val(g), &zero, 1, ""); | ||
| 1177 | LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, return_address_ptr, usize_type_ref, ""); | ||
| 1178 | |||
| 1179 | LLVMValueRef address_value = LLVMBuildPtrToInt(g->builder, return_address, usize_type_ref, ""); | ||
| 1180 | gen_store_untyped(g, address_value, address_slot, 0, false); | 1174 | gen_store_untyped(g, address_value, address_slot, 0, false); |
| 1181 | 1175 | ||
| 1182 | // stack_trace.index += 1; | 1176 | // stack_trace.index += 1; |
| 1183 | LLVMValueRef index_plus_one_val = LLVMBuildAdd(g->builder, index_val, LLVMConstInt(usize_type_ref, 1, false), ""); | 1177 | LLVMValueRef index_plus_one_val = LLVMBuildNUWAdd(g->builder, index_val, LLVMConstInt(usize_type_ref, 1, false), ""); |
| 1184 | gen_store_untyped(g, index_plus_one_val, index_field_ptr, 0, false); | 1178 | gen_store_untyped(g, index_plus_one_val, index_field_ptr, 0, false); |
| 1185 | 1179 | ||
| 1186 | // return; | 1180 | // return; |
| ... | @@ -1189,6 +1183,187 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) { | ... | @@ -1189,6 +1183,187 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) { |
| 1189 | LLVMPositionBuilderAtEnd(g->builder, prev_block); | 1183 | LLVMPositionBuilderAtEnd(g->builder, prev_block); |
| 1190 | LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); | 1184 | LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); |
| 1191 | 1185 | ||
| 1186 | g->add_error_return_trace_addr_fn_val = fn_val; | ||
| 1187 | return fn_val; | ||
| 1188 | } | ||
| 1189 | |||
| 1190 | static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) { | ||
| 1191 | if (g->merge_err_ret_traces_fn_val) | ||
| 1192 | return g->merge_err_ret_traces_fn_val; | ||
| 1193 | |||
| 1194 | assert(g->stack_trace_type != nullptr); | ||
| 1195 | |||
| 1196 | LLVMTypeRef param_types[] = { | ||
| 1197 | get_ptr_to_stack_trace_type(g)->type_ref, | ||
| 1198 | get_ptr_to_stack_trace_type(g)->type_ref, | ||
| 1199 | }; | ||
| 1200 | LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), param_types, 2, false); | ||
| 1201 | |||
| 1202 | Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_merge_error_return_traces"), false); | ||
| 1203 | LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref); | ||
| 1204 | LLVMSetLinkage(fn_val, LLVMInternalLinkage); | ||
| 1205 | LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); | ||
| 1206 | addLLVMFnAttr(fn_val, "nounwind"); | ||
| 1207 | add_uwtable_attr(g, fn_val); | ||
| 1208 | addLLVMArgAttr(fn_val, (unsigned)0, "nonnull"); | ||
| 1209 | addLLVMArgAttr(fn_val, (unsigned)0, "noalias"); | ||
| 1210 | addLLVMArgAttr(fn_val, (unsigned)0, "writeonly"); | ||
| 1211 | addLLVMArgAttr(fn_val, (unsigned)1, "nonnull"); | ||
| 1212 | addLLVMArgAttr(fn_val, (unsigned)1, "noalias"); | ||
| 1213 | addLLVMArgAttr(fn_val, (unsigned)1, "readonly"); | ||
| 1214 | if (g->build_mode == BuildModeDebug) { | ||
| 1215 | ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true"); | ||
| 1216 | ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr); | ||
| 1217 | } | ||
| 1218 | |||
| 1219 | // this is above the ZigLLVMClearCurrentDebugLocation | ||
| 1220 | LLVMValueRef add_error_return_trace_addr_fn_val = get_add_error_return_trace_addr_fn(g); | ||
| 1221 | |||
| 1222 | LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); | ||
| 1223 | LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); | ||
| 1224 | LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder); | ||
| 1225 | LLVMPositionBuilderAtEnd(g->builder, entry_block); | ||
| 1226 | ZigLLVMClearCurrentDebugLocation(g->builder); | ||
| 1227 | |||
| 1228 | // var frame_index: usize = undefined; | ||
| 1229 | // var frames_left: usize = undefined; | ||
| 1230 | // if (src_stack_trace.index < src_stack_trace.instruction_addresses.len) { | ||
| 1231 | // frame_index = 0; | ||
| 1232 | // frames_left = src_stack_trace.index; | ||
| 1233 | // if (frames_left == 0) return; | ||
| 1234 | // } else { | ||
| 1235 | // frame_index = (src_stack_trace.index + 1) % src_stack_trace.instruction_addresses.len; | ||
| 1236 | // frames_left = src_stack_trace.instruction_addresses.len; | ||
| 1237 | // } | ||
| 1238 | // while (true) { | ||
| 1239 | // __zig_add_err_ret_trace_addr(dest_stack_trace, src_stack_trace.instruction_addresses[frame_index]); | ||
| 1240 | // frames_left -= 1; | ||
| 1241 | // if (frames_left == 0) return; | ||
| 1242 | // frame_index = (frame_index + 1) % src_stack_trace.instruction_addresses.len; | ||
| 1243 | // } | ||
| 1244 | LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(fn_val, "Return"); | ||
| 1245 | |||
| 1246 | LLVMValueRef frame_index_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->type_ref, "frame_index"); | ||
| 1247 | LLVMValueRef frames_left_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->type_ref, "frames_left"); | ||
| 1248 | |||
| 1249 | LLVMValueRef dest_stack_trace_ptr = LLVMGetParam(fn_val, 0); | ||
| 1250 | LLVMValueRef src_stack_trace_ptr = LLVMGetParam(fn_val, 1); | ||
| 1251 | |||
| 1252 | size_t src_index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index; | ||
| 1253 | size_t src_addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index; | ||
| 1254 | LLVMValueRef src_index_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr, | ||
| 1255 | (unsigned)src_index_field_index, ""); | ||
| 1256 | LLVMValueRef src_addresses_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr, | ||
| 1257 | (unsigned)src_addresses_field_index, ""); | ||
| 1258 | TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry; | ||
| 1259 | size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index; | ||
| 1260 | LLVMValueRef src_ptr_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)ptr_field_index, ""); | ||
| 1261 | size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index; | ||
| 1262 | LLVMValueRef src_len_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)len_field_index, ""); | ||
| 1263 | LLVMValueRef src_index_val = LLVMBuildLoad(g->builder, src_index_field_ptr, ""); | ||
| 1264 | LLVMValueRef src_ptr_val = LLVMBuildLoad(g->builder, src_ptr_field_ptr, ""); | ||
| 1265 | LLVMValueRef src_len_val = LLVMBuildLoad(g->builder, src_len_field_ptr, ""); | ||
| 1266 | LLVMValueRef no_wrap_bit = LLVMBuildICmp(g->builder, LLVMIntULT, src_index_val, src_len_val, ""); | ||
| 1267 | LLVMBasicBlockRef no_wrap_block = LLVMAppendBasicBlock(fn_val, "NoWrap"); | ||
| 1268 | LLVMBasicBlockRef yes_wrap_block = LLVMAppendBasicBlock(fn_val, "YesWrap"); | ||
| 1269 | LLVMBasicBlockRef loop_block = LLVMAppendBasicBlock(fn_val, "Loop"); | ||
| 1270 | LLVMBuildCondBr(g->builder, no_wrap_bit, no_wrap_block, yes_wrap_block); | ||
| 1271 | |||
| 1272 | LLVMPositionBuilderAtEnd(g->builder, no_wrap_block); | ||
| 1273 | LLVMValueRef usize_zero = LLVMConstNull(g->builtin_types.entry_usize->type_ref); | ||
| 1274 | LLVMBuildStore(g->builder, usize_zero, frame_index_ptr); | ||
| 1275 | LLVMBuildStore(g->builder, src_index_val, frames_left_ptr); | ||
| 1276 | LLVMValueRef frames_left_eq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, src_index_val, usize_zero, ""); | ||
| 1277 | LLVMBuildCondBr(g->builder, frames_left_eq_zero_bit, return_block, loop_block); | ||
| 1278 | |||
| 1279 | LLVMPositionBuilderAtEnd(g->builder, yes_wrap_block); | ||
| 1280 | LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->type_ref, 1, false); | ||
| 1281 | LLVMValueRef plus_one = LLVMBuildNUWAdd(g->builder, src_index_val, usize_one, ""); | ||
| 1282 | LLVMValueRef mod_len = LLVMBuildURem(g->builder, plus_one, src_len_val, ""); | ||
| 1283 | LLVMBuildStore(g->builder, mod_len, frame_index_ptr); | ||
| 1284 | LLVMBuildStore(g->builder, src_len_val, frames_left_ptr); | ||
| 1285 | LLVMBuildBr(g->builder, loop_block); | ||
| 1286 | |||
| 1287 | LLVMPositionBuilderAtEnd(g->builder, loop_block); | ||
| 1288 | LLVMValueRef ptr_index = LLVMBuildLoad(g->builder, frame_index_ptr, ""); | ||
| 1289 | LLVMValueRef addr_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr_val, &ptr_index, 1, ""); | ||
| 1290 | LLVMValueRef this_addr_val = LLVMBuildLoad(g->builder, addr_ptr, ""); | ||
| 1291 | LLVMValueRef args[] = {dest_stack_trace_ptr, this_addr_val}; | ||
| 1292 | ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, ""); | ||
| 1293 | LLVMValueRef prev_frames_left = LLVMBuildLoad(g->builder, frames_left_ptr, ""); | ||
| 1294 | LLVMValueRef new_frames_left = LLVMBuildNUWSub(g->builder, prev_frames_left, usize_one, ""); | ||
| 1295 | LLVMValueRef done_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, new_frames_left, usize_zero, ""); | ||
| 1296 | LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(fn_val, "Continue"); | ||
| 1297 | LLVMBuildCondBr(g->builder, done_bit, return_block, continue_block); | ||
| 1298 | |||
| 1299 | LLVMPositionBuilderAtEnd(g->builder, return_block); | ||
| 1300 | LLVMBuildRetVoid(g->builder); | ||
| 1301 | |||
| 1302 | LLVMPositionBuilderAtEnd(g->builder, continue_block); | ||
| 1303 | LLVMBuildStore(g->builder, new_frames_left, frames_left_ptr); | ||
| 1304 | LLVMValueRef prev_index = LLVMBuildLoad(g->builder, frame_index_ptr, ""); | ||
| 1305 | LLVMValueRef index_plus_one = LLVMBuildNUWAdd(g->builder, prev_index, usize_one, ""); | ||
| 1306 | LLVMValueRef index_mod_len = LLVMBuildURem(g->builder, index_plus_one, src_len_val, ""); | ||
| 1307 | LLVMBuildStore(g->builder, index_mod_len, frame_index_ptr); | ||
| 1308 | LLVMBuildBr(g->builder, loop_block); | ||
| 1309 | |||
| 1310 | LLVMPositionBuilderAtEnd(g->builder, prev_block); | ||
| 1311 | LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); | ||
| 1312 | |||
| 1313 | g->merge_err_ret_traces_fn_val = fn_val; | ||
| 1314 | return fn_val; | ||
| 1315 | |||
| 1316 | } | ||
| 1317 | |||
| 1318 | static LLVMValueRef get_return_err_fn(CodeGen *g) { | ||
| 1319 | if (g->return_err_fn != nullptr) | ||
| 1320 | return g->return_err_fn; | ||
| 1321 | |||
| 1322 | assert(g->err_tag_type != nullptr); | ||
| 1323 | |||
| 1324 | LLVMTypeRef arg_types[] = { | ||
| 1325 | // error return trace pointer | ||
| 1326 | get_ptr_to_stack_trace_type(g)->type_ref, | ||
| 1327 | }; | ||
| 1328 | LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false); | ||
| 1329 | |||
| 1330 | Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_return_error"), false); | ||
| 1331 | LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref); | ||
| 1332 | addLLVMFnAttr(fn_val, "noinline"); // so that we can look at return address | ||
| 1333 | addLLVMFnAttr(fn_val, "cold"); | ||
| 1334 | LLVMSetLinkage(fn_val, LLVMInternalLinkage); | ||
| 1335 | LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); | ||
| 1336 | addLLVMFnAttr(fn_val, "nounwind"); | ||
| 1337 | add_uwtable_attr(g, fn_val); | ||
| 1338 | addLLVMArgAttr(fn_val, (unsigned)0, "nonnull"); | ||
| 1339 | if (g->build_mode == BuildModeDebug) { | ||
| 1340 | ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true"); | ||
| 1341 | ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr); | ||
| 1342 | } | ||
| 1343 | |||
| 1344 | // this is above the ZigLLVMClearCurrentDebugLocation | ||
| 1345 | LLVMValueRef add_error_return_trace_addr_fn_val = get_add_error_return_trace_addr_fn(g); | ||
| 1346 | |||
| 1347 | LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); | ||
| 1348 | LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); | ||
| 1349 | LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder); | ||
| 1350 | LLVMPositionBuilderAtEnd(g->builder, entry_block); | ||
| 1351 | ZigLLVMClearCurrentDebugLocation(g->builder); | ||
| 1352 | |||
| 1353 | LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0); | ||
| 1354 | |||
| 1355 | LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->type_ref; | ||
| 1356 | LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref); | ||
| 1357 | LLVMValueRef return_address_ptr = LLVMBuildCall(g->builder, get_return_address_fn_val(g), &zero, 1, ""); | ||
| 1358 | LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, return_address_ptr, usize_type_ref, ""); | ||
| 1359 | |||
| 1360 | LLVMValueRef args[] = { err_ret_trace_ptr, return_address }; | ||
| 1361 | ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, ""); | ||
| 1362 | LLVMBuildRetVoid(g->builder); | ||
| 1363 | |||
| 1364 | LLVMPositionBuilderAtEnd(g->builder, prev_block); | ||
| 1365 | LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); | ||
| 1366 | |||
| 1192 | g->return_err_fn = fn_val; | 1367 | g->return_err_fn = fn_val; |
| 1193 | return fn_val; | 1368 | return fn_val; |
| 1194 | } | 1369 | } |
| ... | @@ -1641,7 +1816,6 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut | ... | @@ -1641,7 +1816,6 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut |
| 1641 | }; | 1816 | }; |
| 1642 | LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1, | 1817 | LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1, |
| 1643 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); | 1818 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); |
| 1644 | LLVMSetTailCall(call_instruction, true); | ||
| 1645 | return call_instruction; | 1819 | return call_instruction; |
| 1646 | } | 1820 | } |
| 1647 | 1821 | ||
| ... | @@ -4204,6 +4378,27 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable, | ... | @@ -4204,6 +4378,27 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable, |
| 4204 | return LLVMBuildIntToPtr(g->builder, uncasted_result, operand_type->type_ref, ""); | 4378 | return LLVMBuildIntToPtr(g->builder, uncasted_result, operand_type->type_ref, ""); |
| 4205 | } | 4379 | } |
| 4206 | 4380 | ||
| 4381 | static LLVMValueRef ir_render_merge_err_ret_traces(CodeGen *g, IrExecutable *executable, | ||
| 4382 | IrInstructionMergeErrRetTraces *instruction) | ||
| 4383 | { | ||
| 4384 | assert(g->have_err_ret_tracing); | ||
| 4385 | |||
| 4386 | LLVMValueRef src_trace_ptr = ir_llvm_value(g, instruction->src_err_ret_trace_ptr); | ||
| 4387 | LLVMValueRef dest_trace_ptr = ir_llvm_value(g, instruction->dest_err_ret_trace_ptr); | ||
| 4388 | |||
| 4389 | LLVMValueRef args[] = { dest_trace_ptr, src_trace_ptr }; | ||
| 4390 | ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); | ||
| 4391 | return nullptr; | ||
| 4392 | } | ||
| 4393 | |||
| 4394 | static LLVMValueRef ir_render_mark_err_ret_trace_ptr(CodeGen *g, IrExecutable *executable, | ||
| 4395 | IrInstructionMarkErrRetTracePtr *instruction) | ||
| 4396 | { | ||
| 4397 | assert(g->have_err_ret_tracing); | ||
| 4398 | g->cur_err_ret_trace_val_stack = ir_llvm_value(g, instruction->err_ret_trace_ptr); | ||
| 4399 | return nullptr; | ||
| 4400 | } | ||
| 4401 | |||
| 4207 | static void set_debug_location(CodeGen *g, IrInstruction *instruction) { | 4402 | static void set_debug_location(CodeGen *g, IrInstruction *instruction) { |
| 4208 | AstNode *source_node = instruction->source_node; | 4403 | AstNode *source_node = instruction->source_node; |
| 4209 | Scope *scope = instruction->scope; | 4404 | Scope *scope = instruction->scope; |
| ... | @@ -4421,6 +4616,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -4421,6 +4616,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 4421 | return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction); | 4616 | return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction); |
| 4422 | case IrInstructionIdSaveErrRetAddr: | 4617 | case IrInstructionIdSaveErrRetAddr: |
| 4423 | return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction); | 4618 | return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction); |
| 4619 | case IrInstructionIdMergeErrRetTraces: | ||
| 4620 | return ir_render_merge_err_ret_traces(g, executable, (IrInstructionMergeErrRetTraces *)instruction); | ||
| 4621 | case IrInstructionIdMarkErrRetTracePtr: | ||
| 4622 | return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction); | ||
| 4424 | } | 4623 | } |
| 4425 | zig_unreachable(); | 4624 | zig_unreachable(); |
| 4426 | } | 4625 | } |
| ... | @@ -5310,38 +5509,14 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -5310,38 +5509,14 @@ static void do_code_gen(CodeGen *g) { |
| 5310 | g->cur_err_ret_trace_val_arg = nullptr; | 5509 | g->cur_err_ret_trace_val_arg = nullptr; |
| 5311 | } | 5510 | } |
| 5312 | 5511 | ||
| 5512 | // error return tracing setup | ||
| 5313 | bool is_async = fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync; | 5513 | bool is_async = fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync; |
| 5314 | bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn && | 5514 | bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn && !is_async && !have_err_ret_trace_arg; |
| 5315 | (is_async || !have_err_ret_trace_arg); | 5515 | LLVMValueRef err_ret_array_val = nullptr; |
| 5316 | if (have_err_ret_trace_stack) { | 5516 | if (have_err_ret_trace_stack) { |
| 5317 | // TODO call graph analysis to find out what this number needs to be for every function | 5517 | TypeTableEntry *array_type = get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count); |
| 5318 | static const size_t stack_trace_ptr_count = 30; | 5518 | err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses", get_abi_alignment(g, array_type)); |
| 5319 | |||
| 5320 | TypeTableEntry *usize = g->builtin_types.entry_usize; | ||
| 5321 | TypeTableEntry *array_type = get_array_type(g, usize, stack_trace_ptr_count); | ||
| 5322 | LLVMValueRef err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses", | ||
| 5323 | get_abi_alignment(g, array_type)); | ||
| 5324 | g->cur_err_ret_trace_val_stack = build_alloca(g, g->stack_trace_type, "error_return_trace", get_abi_alignment(g, g->stack_trace_type)); | 5519 | g->cur_err_ret_trace_val_stack = build_alloca(g, g->stack_trace_type, "error_return_trace", get_abi_alignment(g, g->stack_trace_type)); |
| 5325 | size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index; | ||
| 5326 | LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)index_field_index, ""); | ||
| 5327 | gen_store_untyped(g, LLVMConstNull(usize->type_ref), index_field_ptr, 0, false); | ||
| 5328 | |||
| 5329 | size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index; | ||
| 5330 | LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)addresses_field_index, ""); | ||
| 5331 | |||
| 5332 | TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry; | ||
| 5333 | size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index; | ||
| 5334 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)ptr_field_index, ""); | ||
| 5335 | LLVMValueRef zero = LLVMConstNull(usize->type_ref); | ||
| 5336 | LLVMValueRef indices[] = {zero, zero}; | ||
| 5337 | LLVMValueRef err_ret_array_val_elem0_ptr = LLVMBuildInBoundsGEP(g->builder, err_ret_array_val, | ||
| 5338 | indices, 2, ""); | ||
| 5339 | gen_store(g, err_ret_array_val_elem0_ptr, ptr_field_ptr, | ||
| 5340 | get_pointer_to_type(g, get_pointer_to_type(g, usize, false), false)); | ||
| 5341 | |||
| 5342 | size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index; | ||
| 5343 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, ""); | ||
| 5344 | gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false)); | ||
| 5345 | } else { | 5520 | } else { |
| 5346 | g->cur_err_ret_trace_val_stack = nullptr; | 5521 | g->cur_err_ret_trace_val_stack = nullptr; |
| 5347 | } | 5522 | } |
| ... | @@ -5436,6 +5611,31 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -5436,6 +5611,31 @@ static void do_code_gen(CodeGen *g) { |
| 5436 | } | 5611 | } |
| 5437 | } | 5612 | } |
| 5438 | 5613 | ||
| 5614 | // finishing error return trace setup. we have to do this after all the allocas. | ||
| 5615 | if (have_err_ret_trace_stack) { | ||
| 5616 | TypeTableEntry *usize = g->builtin_types.entry_usize; | ||
| 5617 | size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index; | ||
| 5618 | LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)index_field_index, ""); | ||
| 5619 | gen_store_untyped(g, LLVMConstNull(usize->type_ref), index_field_ptr, 0, false); | ||
| 5620 | |||
| 5621 | size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index; | ||
| 5622 | LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)addresses_field_index, ""); | ||
| 5623 | |||
| 5624 | TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry; | ||
| 5625 | size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index; | ||
| 5626 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)ptr_field_index, ""); | ||
| 5627 | LLVMValueRef zero = LLVMConstNull(usize->type_ref); | ||
| 5628 | LLVMValueRef indices[] = {zero, zero}; | ||
| 5629 | LLVMValueRef err_ret_array_val_elem0_ptr = LLVMBuildInBoundsGEP(g->builder, err_ret_array_val, | ||
| 5630 | indices, 2, ""); | ||
| 5631 | TypeTableEntry *ptr_ptr_usize_type = get_pointer_to_type(g, get_pointer_to_type(g, usize, false), false); | ||
| 5632 | gen_store(g, err_ret_array_val_elem0_ptr, ptr_field_ptr, ptr_ptr_usize_type); | ||
| 5633 | |||
| 5634 | size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index; | ||
| 5635 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, ""); | ||
| 5636 | gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false)); | ||
| 5637 | } | ||
| 5638 | |||
| 5439 | FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id; | 5639 | FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id; |
| 5440 | 5640 | ||
| 5441 | // create debug variable declarations for parameters | 5641 | // create debug variable declarations for parameters |
| ... | @@ -5943,6 +6143,8 @@ static void define_builtin_compile_vars(CodeGen *g) { | ... | @@ -5943,6 +6143,8 @@ static void define_builtin_compile_vars(CodeGen *g) { |
| 5943 | os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path); | 6143 | os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path); |
| 5944 | Buf *contents = buf_alloc(); | 6144 | Buf *contents = buf_alloc(); |
| 5945 | 6145 | ||
| 6146 | // Modifications to this struct must be coordinated with code that does anything with | ||
| 6147 | // g->stack_trace_type. There are hard-coded references to the field indexes. | ||
| 5946 | buf_append_str(contents, | 6148 | buf_append_str(contents, |
| 5947 | "pub const StackTrace = struct {\n" | 6149 | "pub const StackTrace = struct {\n" |
| 5948 | " index: usize,\n" | 6150 | " index: usize,\n" |
src/ir.cpp+168-72| ... | @@ -725,6 +725,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAddImplicitRetur | ... | @@ -725,6 +725,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAddImplicitRetur |
| 725 | return IrInstructionIdAddImplicitReturnType; | 725 | return IrInstructionIdAddImplicitReturnType; |
| 726 | } | 726 | } |
| 727 | 727 | ||
| 728 | static constexpr IrInstructionId ir_instruction_id(IrInstructionMergeErrRetTraces *) { | ||
| 729 | return IrInstructionIdMergeErrRetTraces; | ||
| 730 | } | ||
| 731 | |||
| 732 | static constexpr IrInstructionId ir_instruction_id(IrInstructionMarkErrRetTracePtr *) { | ||
| 733 | return IrInstructionIdMarkErrRetTracePtr; | ||
| 734 | } | ||
| 735 | |||
| 728 | template<typename T> | 736 | template<typename T> |
| 729 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { | 737 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 730 | T *special_instruction = allocate<T>(1); | 738 | T *special_instruction = allocate<T>(1); |
| ... | @@ -956,25 +964,6 @@ static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, Scope *scope, Ast | ... | @@ -956,25 +964,6 @@ static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, Scope *scope, Ast |
| 956 | return &const_instruction->base; | 964 | return &const_instruction->base; |
| 957 | } | 965 | } |
| 958 | 966 | ||
| 959 | static IrInstruction *ir_build_const_promise_init(IrBuilder *irb, Scope *scope, AstNode *source_node, | ||
| 960 | TypeTableEntry *return_type) | ||
| 961 | { | ||
| 962 | TypeTableEntry *struct_type = get_promise_frame_type(irb->codegen, return_type); | ||
| 963 | |||
| 964 | IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node); | ||
| 965 | const_instruction->base.value.type = struct_type; | ||
| 966 | const_instruction->base.value.special = ConstValSpecialStatic; | ||
| 967 | const_instruction->base.value.data.x_struct.fields = allocate<ConstExprValue>(struct_type->data.structure.src_field_count); | ||
| 968 | const_instruction->base.value.data.x_struct.fields[0].type = struct_type->data.structure.fields[0].type_entry; | ||
| 969 | const_instruction->base.value.data.x_struct.fields[0].special = ConstValSpecialStatic; | ||
| 970 | const_instruction->base.value.data.x_struct.fields[0].data.x_maybe = nullptr; | ||
| 971 | const_instruction->base.value.data.x_struct.fields[1].type = return_type; | ||
| 972 | const_instruction->base.value.data.x_struct.fields[1].special = ConstValSpecialUndef; | ||
| 973 | const_instruction->base.value.data.x_struct.fields[2].type = struct_type->data.structure.fields[2].type_entry; | ||
| 974 | const_instruction->base.value.data.x_struct.fields[2].special = ConstValSpecialUndef; | ||
| 975 | return &const_instruction->base; | ||
| 976 | } | ||
| 977 | |||
| 978 | static IrInstruction *ir_build_bin_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrBinOp op_id, | 967 | static IrInstruction *ir_build_bin_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrBinOp op_id, |
| 979 | IrInstruction *op1, IrInstruction *op2, bool safety_check_on) | 968 | IrInstruction *op1, IrInstruction *op2, bool safety_check_on) |
| 980 | { | 969 | { |
| ... | @@ -2495,8 +2484,9 @@ static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *s | ... | @@ -2495,8 +2484,9 @@ static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *s |
| 2495 | return &instruction->base; | 2484 | return &instruction->base; |
| 2496 | } | 2485 | } |
| 2497 | 2486 | ||
| 2498 | static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, AstNode *source_node) { | 2487 | static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstructionErrorReturnTrace::Nullable nullable) { |
| 2499 | IrInstructionErrorReturnTrace *instruction = ir_build_instruction<IrInstructionErrorReturnTrace>(irb, scope, source_node); | 2488 | IrInstructionErrorReturnTrace *instruction = ir_build_instruction<IrInstructionErrorReturnTrace>(irb, scope, source_node); |
| 2489 | instruction->nullable = nullable; | ||
| 2500 | 2490 | ||
| 2501 | return &instruction->base; | 2491 | return &instruction->base; |
| 2502 | } | 2492 | } |
| ... | @@ -2717,6 +2707,30 @@ static IrInstruction *ir_build_add_implicit_return_type(IrBuilder *irb, Scope *s | ... | @@ -2717,6 +2707,30 @@ static IrInstruction *ir_build_add_implicit_return_type(IrBuilder *irb, Scope *s |
| 2717 | return &instruction->base; | 2707 | return &instruction->base; |
| 2718 | } | 2708 | } |
| 2719 | 2709 | ||
| 2710 | static IrInstruction *ir_build_merge_err_ret_traces(IrBuilder *irb, Scope *scope, AstNode *source_node, | ||
| 2711 | IrInstruction *coro_promise_ptr, IrInstruction *src_err_ret_trace_ptr, IrInstruction *dest_err_ret_trace_ptr) | ||
| 2712 | { | ||
| 2713 | IrInstructionMergeErrRetTraces *instruction = ir_build_instruction<IrInstructionMergeErrRetTraces>(irb, scope, source_node); | ||
| 2714 | instruction->coro_promise_ptr = coro_promise_ptr; | ||
| 2715 | instruction->src_err_ret_trace_ptr = src_err_ret_trace_ptr; | ||
| 2716 | instruction->dest_err_ret_trace_ptr = dest_err_ret_trace_ptr; | ||
| 2717 | |||
| 2718 | ir_ref_instruction(coro_promise_ptr, irb->current_basic_block); | ||
| 2719 | ir_ref_instruction(src_err_ret_trace_ptr, irb->current_basic_block); | ||
| 2720 | ir_ref_instruction(dest_err_ret_trace_ptr, irb->current_basic_block); | ||
| 2721 | |||
| 2722 | return &instruction->base; | ||
| 2723 | } | ||
| 2724 | |||
| 2725 | static IrInstruction *ir_build_mark_err_ret_trace_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *err_ret_trace_ptr) { | ||
| 2726 | IrInstructionMarkErrRetTracePtr *instruction = ir_build_instruction<IrInstructionMarkErrRetTracePtr>(irb, scope, source_node); | ||
| 2727 | instruction->err_ret_trace_ptr = err_ret_trace_ptr; | ||
| 2728 | |||
| 2729 | ir_ref_instruction(err_ret_trace_ptr, irb->current_basic_block); | ||
| 2730 | |||
| 2731 | return &instruction->base; | ||
| 2732 | } | ||
| 2733 | |||
| 2720 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { | 2734 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { |
| 2721 | results[ReturnKindUnconditional] = 0; | 2735 | results[ReturnKindUnconditional] = 0; |
| 2722 | results[ReturnKindError] = 0; | 2736 | results[ReturnKindError] = 0; |
| ... | @@ -2822,34 +2836,6 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode | ... | @@ -2822,34 +2836,6 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode |
| 2822 | // the above blocks are rendered by ir_gen after the rest of codegen | 2836 | // the above blocks are rendered by ir_gen after the rest of codegen |
| 2823 | } | 2837 | } |
| 2824 | 2838 | ||
| 2825 | static bool exec_have_err_ret_trace(CodeGen *g, IrExecutable *exec) { | ||
| 2826 | if (!g->have_err_ret_tracing) | ||
| 2827 | return false; | ||
| 2828 | FnTableEntry *fn_entry = exec_fn_entry(exec); | ||
| 2829 | if (fn_entry == nullptr) | ||
| 2830 | return false; | ||
| 2831 | if (exec->is_inline) | ||
| 2832 | return false; | ||
| 2833 | return type_can_fail(fn_entry->type_entry->data.fn.fn_type_id.return_type); | ||
| 2834 | } | ||
| 2835 | |||
| 2836 | static void ir_gen_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *node) { | ||
| 2837 | if (!exec_have_err_ret_trace(irb->codegen, irb->exec)) | ||
| 2838 | return; | ||
| 2839 | |||
| 2840 | bool is_async = exec_is_async(irb->exec); | ||
| 2841 | |||
| 2842 | if (is_async) { | ||
| 2843 | //IrInstruction *err_ret_addr_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_err_ret_addr_ptr); | ||
| 2844 | //IrInstruction *return_address_ptr = ir_build_instr_addr(irb, scope, node); | ||
| 2845 | //IrInstruction *return_address_usize = ir_build_ptr_to_int(irb, scope, node, return_address_ptr); | ||
| 2846 | //ir_build_store_ptr(irb, scope, node, err_ret_addr_ptr, return_address_usize); | ||
| 2847 | return; | ||
| 2848 | } | ||
| 2849 | |||
| 2850 | ir_build_save_err_ret_addr(irb, scope, node); | ||
| 2851 | } | ||
| 2852 | |||
| 2853 | static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) { | 2839 | static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) { |
| 2854 | assert(node->type == NodeTypeReturnExpr); | 2840 | assert(node->type == NodeTypeReturnExpr); |
| 2855 | 2841 | ||
| ... | @@ -2895,8 +2881,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, | ... | @@ -2895,8 +2881,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 2895 | 2881 | ||
| 2896 | IrInstruction *is_err = ir_build_test_err(irb, scope, node, return_value); | 2882 | IrInstruction *is_err = ir_build_test_err(irb, scope, node, return_value); |
| 2897 | 2883 | ||
| 2884 | bool should_inline = ir_should_inline(irb->exec, scope); | ||
| 2898 | IrInstruction *is_comptime; | 2885 | IrInstruction *is_comptime; |
| 2899 | if (ir_should_inline(irb->exec, scope)) { | 2886 | if (should_inline) { |
| 2900 | is_comptime = ir_build_const_bool(irb, scope, node, true); | 2887 | is_comptime = ir_build_const_bool(irb, scope, node, true); |
| 2901 | } else { | 2888 | } else { |
| 2902 | is_comptime = ir_build_test_comptime(irb, scope, node, is_err); | 2889 | is_comptime = ir_build_test_comptime(irb, scope, node, is_err); |
| ... | @@ -2909,7 +2896,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, | ... | @@ -2909,7 +2896,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 2909 | if (have_err_defers) { | 2896 | if (have_err_defers) { |
| 2910 | ir_gen_defers_for_block(irb, scope, outer_scope, true); | 2897 | ir_gen_defers_for_block(irb, scope, outer_scope, true); |
| 2911 | } | 2898 | } |
| 2912 | ir_gen_save_err_ret_addr(irb, scope, node); | 2899 | if (irb->codegen->have_err_ret_tracing && !should_inline) { |
| 2900 | ir_build_save_err_ret_addr(irb, scope, node); | ||
| 2901 | } | ||
| 2913 | ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); | 2902 | ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); |
| 2914 | 2903 | ||
| 2915 | ir_set_cursor_at_end_and_append_block(irb, ok_block); | 2904 | ir_set_cursor_at_end_and_append_block(irb, ok_block); |
| ... | @@ -2938,7 +2927,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, | ... | @@ -2938,7 +2927,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 2938 | IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn"); | 2927 | IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn"); |
| 2939 | IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue"); | 2928 | IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue"); |
| 2940 | IrInstruction *is_comptime; | 2929 | IrInstruction *is_comptime; |
| 2941 | if (ir_should_inline(irb->exec, scope)) { | 2930 | bool should_inline = ir_should_inline(irb->exec, scope); |
| 2931 | if (should_inline) { | ||
| 2942 | is_comptime = ir_build_const_bool(irb, scope, node, true); | 2932 | is_comptime = ir_build_const_bool(irb, scope, node, true); |
| 2943 | } else { | 2933 | } else { |
| 2944 | is_comptime = ir_build_test_comptime(irb, scope, node, is_err_val); | 2934 | is_comptime = ir_build_test_comptime(irb, scope, node, is_err_val); |
| ... | @@ -2948,7 +2938,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, | ... | @@ -2948,7 +2938,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 2948 | ir_set_cursor_at_end_and_append_block(irb, return_block); | 2938 | ir_set_cursor_at_end_and_append_block(irb, return_block); |
| 2949 | ir_gen_defers_for_block(irb, scope, outer_scope, true); | 2939 | ir_gen_defers_for_block(irb, scope, outer_scope, true); |
| 2950 | IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr); | 2940 | IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr); |
| 2951 | ir_gen_save_err_ret_addr(irb, scope, node); | 2941 | if (irb->codegen->have_err_ret_tracing && !should_inline) { |
| 2942 | ir_build_save_err_ret_addr(irb, scope, node); | ||
| 2943 | } | ||
| 2952 | ir_gen_async_return(irb, scope, node, err_val, false); | 2944 | ir_gen_async_return(irb, scope, node, err_val, false); |
| 2953 | 2945 | ||
| 2954 | ir_set_cursor_at_end_and_append_block(irb, continue_block); | 2946 | ir_set_cursor_at_end_and_append_block(irb, continue_block); |
| ... | @@ -4242,7 +4234,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -4242,7 +4234,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4242 | } | 4234 | } |
| 4243 | case BuiltinFnIdErrorReturnTrace: | 4235 | case BuiltinFnIdErrorReturnTrace: |
| 4244 | { | 4236 | { |
| 4245 | return ir_build_error_return_trace(irb, scope, node); | 4237 | return ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::Null); |
| 4246 | } | 4238 | } |
| 4247 | case BuiltinFnIdAtomicRmw: | 4239 | case BuiltinFnIdAtomicRmw: |
| 4248 | { | 4240 | { |
| ... | @@ -6125,6 +6117,13 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast | ... | @@ -6125,6 +6117,13 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast |
| 6125 | Buf *result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME); | 6117 | Buf *result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME); |
| 6126 | IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_ptr_field_name); | 6118 | IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_ptr_field_name); |
| 6127 | 6119 | ||
| 6120 | if (irb->codegen->have_err_ret_tracing) { | ||
| 6121 | IrInstruction *err_ret_trace_ptr = ir_build_error_return_trace(irb, parent_scope, node, IrInstructionErrorReturnTrace::NonNull); | ||
| 6122 | Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME); | ||
| 6123 | IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name); | ||
| 6124 | ir_build_store_ptr(irb, parent_scope, node, err_ret_trace_ptr_field_ptr, err_ret_trace_ptr); | ||
| 6125 | } | ||
| 6126 | |||
| 6128 | Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME); | 6127 | Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME); |
| 6129 | IrInstruction *awaiter_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, | 6128 | IrInstruction *awaiter_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, |
| 6130 | awaiter_handle_field_name); | 6129 | awaiter_handle_field_name); |
| ... | @@ -6148,10 +6147,16 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast | ... | @@ -6148,10 +6147,16 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast |
| 6148 | IrInstruction *is_non_null = ir_build_test_nonnull(irb, parent_scope, node, maybe_await_handle); | 6147 | IrInstruction *is_non_null = ir_build_test_nonnull(irb, parent_scope, node, maybe_await_handle); |
| 6149 | IrBasicBlock *yes_suspend_block = ir_create_basic_block(irb, parent_scope, "YesSuspend"); | 6148 | IrBasicBlock *yes_suspend_block = ir_create_basic_block(irb, parent_scope, "YesSuspend"); |
| 6150 | IrBasicBlock *no_suspend_block = ir_create_basic_block(irb, parent_scope, "NoSuspend"); | 6149 | IrBasicBlock *no_suspend_block = ir_create_basic_block(irb, parent_scope, "NoSuspend"); |
| 6151 | IrBasicBlock *merge_block = ir_create_basic_block(irb, parent_scope, "Merge"); | 6150 | IrBasicBlock *merge_block = ir_create_basic_block(irb, parent_scope, "MergeSuspend"); |
| 6152 | ir_build_cond_br(irb, parent_scope, node, is_non_null, no_suspend_block, yes_suspend_block, const_bool_false); | 6151 | ir_build_cond_br(irb, parent_scope, node, is_non_null, no_suspend_block, yes_suspend_block, const_bool_false); |
| 6153 | 6152 | ||
| 6154 | ir_set_cursor_at_end_and_append_block(irb, no_suspend_block); | 6153 | ir_set_cursor_at_end_and_append_block(irb, no_suspend_block); |
| 6154 | if (irb->codegen->have_err_ret_tracing) { | ||
| 6155 | Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME); | ||
| 6156 | IrInstruction *src_err_ret_trace_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, err_ret_trace_field_name); | ||
| 6157 | IrInstruction *dest_err_ret_trace_ptr = ir_build_error_return_trace(irb, parent_scope, node, IrInstructionErrorReturnTrace::NonNull); | ||
| 6158 | ir_build_merge_err_ret_traces(irb, parent_scope, node, coro_promise_ptr, src_err_ret_trace_ptr, dest_err_ret_trace_ptr); | ||
| 6159 | } | ||
| 6155 | Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME); | 6160 | Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME); |
| 6156 | IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_field_name); | 6161 | IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_field_name); |
| 6157 | IrInstruction *no_suspend_result = ir_build_load_ptr(irb, parent_scope, node, promise_result_ptr); | 6162 | IrInstruction *no_suspend_result = ir_build_load_ptr(irb, parent_scope, node, promise_result_ptr); |
| ... | @@ -6407,6 +6412,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec | ... | @@ -6407,6 +6412,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 6407 | IrInstruction *coro_id; | 6412 | IrInstruction *coro_id; |
| 6408 | IrInstruction *u8_ptr_type; | 6413 | IrInstruction *u8_ptr_type; |
| 6409 | IrInstruction *const_bool_false; | 6414 | IrInstruction *const_bool_false; |
| 6415 | IrInstruction *coro_promise_ptr; | ||
| 6416 | IrInstruction *err_ret_trace_ptr; | ||
| 6410 | TypeTableEntry *return_type; | 6417 | TypeTableEntry *return_type; |
| 6411 | Buf *result_ptr_field_name; | 6418 | Buf *result_ptr_field_name; |
| 6412 | VariableTableEntry *coro_size_var; | 6419 | VariableTableEntry *coro_size_var; |
| ... | @@ -6417,9 +6424,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec | ... | @@ -6417,9 +6424,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 6417 | VariableTableEntry *promise_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); | 6424 | VariableTableEntry *promise_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); |
| 6418 | 6425 | ||
| 6419 | return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type; | 6426 | return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type; |
| 6420 | IrInstruction *promise_init = ir_build_const_promise_init(irb, coro_scope, node, return_type); | 6427 | IrInstruction *undef = ir_build_const_undefined(irb, coro_scope, node); |
| 6421 | ir_build_var_decl(irb, coro_scope, node, promise_var, nullptr, nullptr, promise_init); | 6428 | TypeTableEntry *coro_frame_type = get_promise_frame_type(irb->codegen, return_type); |
| 6422 | IrInstruction *coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var, false, false); | 6429 | IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type); |
| 6430 | // TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa | ||
| 6431 | ir_build_var_decl(irb, coro_scope, node, promise_var, coro_frame_type_value, nullptr, undef); | ||
| 6432 | coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var, false, false); | ||
| 6423 | 6433 | ||
| 6424 | VariableTableEntry *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); | 6434 | VariableTableEntry *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); |
| 6425 | IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node); | 6435 | IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node); |
| ... | @@ -6452,7 +6462,6 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec | ... | @@ -6452,7 +6462,6 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 6452 | ir_set_cursor_at_end_and_append_block(irb, alloc_err_block); | 6462 | ir_set_cursor_at_end_and_append_block(irb, alloc_err_block); |
| 6453 | // we can return undefined here, because the caller passes a pointer to the error struct field | 6463 | // we can return undefined here, because the caller passes a pointer to the error struct field |
| 6454 | // in the error union result, and we populate it in case of allocation failure. | 6464 | // in the error union result, and we populate it in case of allocation failure. |
| 6455 | IrInstruction *undef = ir_build_const_undefined(irb, coro_scope, node); | ||
| 6456 | ir_build_return(irb, coro_scope, node, undef); | 6465 | ir_build_return(irb, coro_scope, node, undef); |
| 6457 | 6466 | ||
| 6458 | ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block); | 6467 | ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block); |
| ... | @@ -6460,13 +6469,35 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec | ... | @@ -6460,13 +6469,35 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 6460 | irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr); | 6469 | irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr); |
| 6461 | 6470 | ||
| 6462 | Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME); | 6471 | Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME); |
| 6463 | irb->exec->coro_awaiter_field_ptr = ir_build_field_ptr(irb, coro_scope, node, coro_promise_ptr, | 6472 | irb->exec->coro_awaiter_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, |
| 6464 | awaiter_handle_field_name); | 6473 | awaiter_handle_field_name); |
| 6474 | ir_build_store_ptr(irb, scope, node, irb->exec->coro_awaiter_field_ptr, null_value); | ||
| 6465 | Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME); | 6475 | Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME); |
| 6466 | irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, coro_scope, node, coro_promise_ptr, result_field_name); | 6476 | irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name); |
| 6467 | result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME); | 6477 | result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME); |
| 6468 | irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, coro_scope, node, coro_promise_ptr, result_ptr_field_name); | 6478 | irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name); |
| 6469 | ir_build_store_ptr(irb, coro_scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr); | 6479 | ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr); |
| 6480 | if (irb->codegen->have_err_ret_tracing) { | ||
| 6481 | // initialize the error return trace | ||
| 6482 | Buf *return_addresses_field_name = buf_create_from_str(RETURN_ADDRESSES_FIELD_NAME); | ||
| 6483 | IrInstruction *return_addresses_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, return_addresses_field_name); | ||
| 6484 | |||
| 6485 | Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME); | ||
| 6486 | err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name); | ||
| 6487 | ir_build_mark_err_ret_trace_ptr(irb, scope, node, err_ret_trace_ptr); | ||
| 6488 | |||
| 6489 | // coordinate with builtin.zig | ||
| 6490 | Buf *index_name = buf_create_from_str("index"); | ||
| 6491 | IrInstruction *index_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, index_name); | ||
| 6492 | IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0); | ||
| 6493 | ir_build_store_ptr(irb, scope, node, index_ptr, zero); | ||
| 6494 | |||
| 6495 | Buf *instruction_addresses_name = buf_create_from_str("instruction_addresses"); | ||
| 6496 | IrInstruction *addrs_slice_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, instruction_addresses_name); | ||
| 6497 | |||
| 6498 | IrInstruction *slice_value = ir_build_slice(irb, scope, node, return_addresses_ptr, zero, nullptr, false); | ||
| 6499 | ir_build_store_ptr(irb, scope, node, addrs_slice_ptr, slice_value); | ||
| 6500 | } | ||
| 6470 | 6501 | ||
| 6471 | 6502 | ||
| 6472 | irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal"); | 6503 | irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal"); |
| ... | @@ -6517,6 +6548,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec | ... | @@ -6517,6 +6548,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 6517 | IrInstruction *size_of_ret_val = ir_build_size_of(irb, scope, node, return_type_inst); | 6548 | IrInstruction *size_of_ret_val = ir_build_size_of(irb, scope, node, return_type_inst); |
| 6518 | ir_build_memcpy(irb, scope, node, result_ptr_as_u8_ptr, return_value_ptr_as_u8_ptr, size_of_ret_val); | 6549 | ir_build_memcpy(irb, scope, node, result_ptr_as_u8_ptr, return_value_ptr_as_u8_ptr, size_of_ret_val); |
| 6519 | } | 6550 | } |
| 6551 | if (irb->codegen->have_err_ret_tracing) { | ||
| 6552 | Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME); | ||
| 6553 | IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name); | ||
| 6554 | IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr); | ||
| 6555 | ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr, dest_err_ret_trace_ptr); | ||
| 6556 | } | ||
| 6520 | ir_build_br(irb, scope, node, check_free_block, const_bool_false); | 6557 | ir_build_br(irb, scope, node, check_free_block, const_bool_false); |
| 6521 | 6558 | ||
| 6522 | ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block); | 6559 | ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block); |
| ... | @@ -11579,18 +11616,25 @@ static bool exec_has_err_ret_trace(CodeGen *g, IrExecutable *exec) { | ... | @@ -11579,18 +11616,25 @@ static bool exec_has_err_ret_trace(CodeGen *g, IrExecutable *exec) { |
| 11579 | static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira, | 11616 | static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira, |
| 11580 | IrInstructionErrorReturnTrace *instruction) | 11617 | IrInstructionErrorReturnTrace *instruction) |
| 11581 | { | 11618 | { |
| 11582 | TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen); | 11619 | if (instruction->nullable == IrInstructionErrorReturnTrace::Null) { |
| 11583 | TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type); | 11620 | TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen); |
| 11584 | if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) { | 11621 | TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type); |
| 11585 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | 11622 | if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) { |
| 11586 | out_val->data.x_maybe = nullptr; | 11623 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 11624 | out_val->data.x_maybe = nullptr; | ||
| 11625 | return nullable_type; | ||
| 11626 | } | ||
| 11627 | IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope, | ||
| 11628 | instruction->base.source_node, instruction->nullable); | ||
| 11629 | ir_link_new_instruction(new_instruction, &instruction->base); | ||
| 11587 | return nullable_type; | 11630 | return nullable_type; |
| 11631 | } else { | ||
| 11632 | assert(ira->codegen->have_err_ret_tracing); | ||
| 11633 | IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope, | ||
| 11634 | instruction->base.source_node, instruction->nullable); | ||
| 11635 | ir_link_new_instruction(new_instruction, &instruction->base); | ||
| 11636 | return get_ptr_to_stack_trace_type(ira->codegen); | ||
| 11588 | } | 11637 | } |
| 11589 | |||
| 11590 | IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope, | ||
| 11591 | instruction->base.source_node); | ||
| 11592 | ir_link_new_instruction(new_instruction, &instruction->base); | ||
| 11593 | return nullable_type; | ||
| 11594 | } | 11638 | } |
| 11595 | 11639 | ||
| 11596 | static TypeTableEntry *ir_analyze_instruction_error_union(IrAnalyze *ira, | 11640 | static TypeTableEntry *ir_analyze_instruction_error_union(IrAnalyze *ira, |
| ... | @@ -13072,6 +13116,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira, | ... | @@ -13072,6 +13116,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira, |
| 13072 | { | 13116 | { |
| 13073 | if (!is_slice(bare_struct_type)) { | 13117 | if (!is_slice(bare_struct_type)) { |
| 13074 | ScopeDecls *container_scope = get_container_scope(bare_struct_type); | 13118 | ScopeDecls *container_scope = get_container_scope(bare_struct_type); |
| 13119 | assert(container_scope != nullptr); | ||
| 13075 | auto entry = container_scope->decl_table.maybe_get(field_name); | 13120 | auto entry = container_scope->decl_table.maybe_get(field_name); |
| 13076 | Tld *tld = entry ? entry->value : nullptr; | 13121 | Tld *tld = entry ? entry->value : nullptr; |
| 13077 | if (tld && tld->id == TldIdFn) { | 13122 | if (tld && tld->id == TldIdFn) { |
| ... | @@ -17904,6 +17949,39 @@ static TypeTableEntry *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira, | ... | @@ -17904,6 +17949,39 @@ static TypeTableEntry *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira, |
| 17904 | return out_val->type; | 17949 | return out_val->type; |
| 17905 | } | 17950 | } |
| 17906 | 17951 | ||
| 17952 | static TypeTableEntry *ir_analyze_instruction_merge_err_ret_traces(IrAnalyze *ira, | ||
| 17953 | IrInstructionMergeErrRetTraces *instruction) | ||
| 17954 | { | ||
| 17955 | IrInstruction *coro_promise_ptr = instruction->coro_promise_ptr->other; | ||
| 17956 | if (type_is_invalid(coro_promise_ptr->value.type)) | ||
| 17957 | return ira->codegen->builtin_types.entry_invalid; | ||
| 17958 | |||
| 17959 | assert(coro_promise_ptr->value.type->id == TypeTableEntryIdPointer); | ||
| 17960 | TypeTableEntry *promise_frame_type = coro_promise_ptr->value.type->data.pointer.child_type; | ||
| 17961 | assert(promise_frame_type->id == TypeTableEntryIdStruct); | ||
| 17962 | TypeTableEntry *promise_result_type = promise_frame_type->data.structure.fields[1].type_entry; | ||
| 17963 | |||
| 17964 | if (!type_can_fail(promise_result_type)) { | ||
| 17965 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | ||
| 17966 | out_val->type = ira->codegen->builtin_types.entry_void; | ||
| 17967 | return out_val->type; | ||
| 17968 | } | ||
| 17969 | |||
| 17970 | IrInstruction *src_err_ret_trace_ptr = instruction->src_err_ret_trace_ptr->other; | ||
| 17971 | if (type_is_invalid(src_err_ret_trace_ptr->value.type)) | ||
| 17972 | return ira->codegen->builtin_types.entry_invalid; | ||
| 17973 | |||
| 17974 | IrInstruction *dest_err_ret_trace_ptr = instruction->dest_err_ret_trace_ptr->other; | ||
| 17975 | if (type_is_invalid(dest_err_ret_trace_ptr->value.type)) | ||
| 17976 | return ira->codegen->builtin_types.entry_invalid; | ||
| 17977 | |||
| 17978 | IrInstruction *result = ir_build_merge_err_ret_traces(&ira->new_irb, instruction->base.scope, | ||
| 17979 | instruction->base.source_node, coro_promise_ptr, src_err_ret_trace_ptr, dest_err_ret_trace_ptr); | ||
| 17980 | ir_link_new_instruction(result, &instruction->base); | ||
| 17981 | result->value.type = ira->codegen->builtin_types.entry_void; | ||
| 17982 | return result->value.type; | ||
| 17983 | } | ||
| 17984 | |||
| 17907 | static TypeTableEntry *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, IrInstructionSaveErrRetAddr *instruction) { | 17985 | static TypeTableEntry *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, IrInstructionSaveErrRetAddr *instruction) { |
| 17908 | IrInstruction *result = ir_build_save_err_ret_addr(&ira->new_irb, instruction->base.scope, | 17986 | IrInstruction *result = ir_build_save_err_ret_addr(&ira->new_irb, instruction->base.scope, |
| 17909 | instruction->base.source_node); | 17987 | instruction->base.source_node); |
| ... | @@ -17912,6 +17990,18 @@ static TypeTableEntry *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, | ... | @@ -17912,6 +17990,18 @@ static TypeTableEntry *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, |
| 17912 | return result->value.type; | 17990 | return result->value.type; |
| 17913 | } | 17991 | } |
| 17914 | 17992 | ||
| 17993 | static TypeTableEntry *ir_analyze_instruction_mark_err_ret_trace_ptr(IrAnalyze *ira, IrInstructionMarkErrRetTracePtr *instruction) { | ||
| 17994 | IrInstruction *err_ret_trace_ptr = instruction->err_ret_trace_ptr->other; | ||
| 17995 | if (type_is_invalid(err_ret_trace_ptr->value.type)) | ||
| 17996 | return ira->codegen->builtin_types.entry_invalid; | ||
| 17997 | |||
| 17998 | IrInstruction *result = ir_build_mark_err_ret_trace_ptr(&ira->new_irb, instruction->base.scope, | ||
| 17999 | instruction->base.source_node, err_ret_trace_ptr); | ||
| 18000 | ir_link_new_instruction(result, &instruction->base); | ||
| 18001 | result->value.type = ira->codegen->builtin_types.entry_void; | ||
| 18002 | return result->value.type; | ||
| 18003 | } | ||
| 18004 | |||
| 17915 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { | 18005 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { |
| 17916 | switch (instruction->id) { | 18006 | switch (instruction->id) { |
| 17917 | case IrInstructionIdInvalid: | 18007 | case IrInstructionIdInvalid: |
| ... | @@ -18155,6 +18245,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi | ... | @@ -18155,6 +18245,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 18155 | return ir_analyze_instruction_save_err_ret_addr(ira, (IrInstructionSaveErrRetAddr *)instruction); | 18245 | return ir_analyze_instruction_save_err_ret_addr(ira, (IrInstructionSaveErrRetAddr *)instruction); |
| 18156 | case IrInstructionIdAddImplicitReturnType: | 18246 | case IrInstructionIdAddImplicitReturnType: |
| 18157 | return ir_analyze_instruction_add_implicit_return_type(ira, (IrInstructionAddImplicitReturnType *)instruction); | 18247 | return ir_analyze_instruction_add_implicit_return_type(ira, (IrInstructionAddImplicitReturnType *)instruction); |
| 18248 | case IrInstructionIdMergeErrRetTraces: | ||
| 18249 | return ir_analyze_instruction_merge_err_ret_traces(ira, (IrInstructionMergeErrRetTraces *)instruction); | ||
| 18250 | case IrInstructionIdMarkErrRetTracePtr: | ||
| 18251 | return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction); | ||
| 18158 | } | 18252 | } |
| 18159 | zig_unreachable(); | 18253 | zig_unreachable(); |
| 18160 | } | 18254 | } |
| ... | @@ -18282,6 +18376,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -18282,6 +18376,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 18282 | case IrInstructionIdAwaitBookkeeping: | 18376 | case IrInstructionIdAwaitBookkeeping: |
| 18283 | case IrInstructionIdSaveErrRetAddr: | 18377 | case IrInstructionIdSaveErrRetAddr: |
| 18284 | case IrInstructionIdAddImplicitReturnType: | 18378 | case IrInstructionIdAddImplicitReturnType: |
| 18379 | case IrInstructionIdMergeErrRetTraces: | ||
| 18380 | case IrInstructionIdMarkErrRetTracePtr: | ||
| 18285 | return true; | 18381 | return true; |
| 18286 | 18382 | ||
| 18287 | case IrInstructionIdPhi: | 18383 | case IrInstructionIdPhi: |
src/ir_print.cpp+32-1| ... | @@ -1024,7 +1024,16 @@ static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) { | ... | @@ -1024,7 +1024,16 @@ static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) { |
| 1024 | } | 1024 | } |
| 1025 | 1025 | ||
| 1026 | static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTrace *instruction) { | 1026 | static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTrace *instruction) { |
| 1027 | fprintf(irp->f, "@errorReturnTrace()"); | 1027 | fprintf(irp->f, "@errorReturnTrace("); |
| 1028 | switch (instruction->nullable) { | ||
| 1029 | case IrInstructionErrorReturnTrace::Null: | ||
| 1030 | fprintf(irp->f, "Null"); | ||
| 1031 | break; | ||
| 1032 | case IrInstructionErrorReturnTrace::NonNull: | ||
| 1033 | fprintf(irp->f, "NonNull"); | ||
| 1034 | break; | ||
| 1035 | } | ||
| 1036 | fprintf(irp->f, ")"); | ||
| 1028 | } | 1037 | } |
| 1029 | 1038 | ||
| 1030 | static void ir_print_error_union(IrPrint *irp, IrInstructionErrorUnion *instruction) { | 1039 | static void ir_print_error_union(IrPrint *irp, IrInstructionErrorUnion *instruction) { |
| ... | @@ -1179,6 +1188,22 @@ static void ir_print_add_implicit_return_type(IrPrint *irp, IrInstructionAddImpl | ... | @@ -1179,6 +1188,22 @@ static void ir_print_add_implicit_return_type(IrPrint *irp, IrInstructionAddImpl |
| 1179 | fprintf(irp->f, ")"); | 1188 | fprintf(irp->f, ")"); |
| 1180 | } | 1189 | } |
| 1181 | 1190 | ||
| 1191 | static void ir_print_merge_err_ret_traces(IrPrint *irp, IrInstructionMergeErrRetTraces *instruction) { | ||
| 1192 | fprintf(irp->f, "@mergeErrRetTraces("); | ||
| 1193 | ir_print_other_instruction(irp, instruction->coro_promise_ptr); | ||
| 1194 | fprintf(irp->f, ","); | ||
| 1195 | ir_print_other_instruction(irp, instruction->src_err_ret_trace_ptr); | ||
| 1196 | fprintf(irp->f, ","); | ||
| 1197 | ir_print_other_instruction(irp, instruction->dest_err_ret_trace_ptr); | ||
| 1198 | fprintf(irp->f, ")"); | ||
| 1199 | } | ||
| 1200 | |||
| 1201 | static void ir_print_mark_err_ret_trace_ptr(IrPrint *irp, IrInstructionMarkErrRetTracePtr *instruction) { | ||
| 1202 | fprintf(irp->f, "@markErrRetTracePtr("); | ||
| 1203 | ir_print_other_instruction(irp, instruction->err_ret_trace_ptr); | ||
| 1204 | fprintf(irp->f, ")"); | ||
| 1205 | } | ||
| 1206 | |||
| 1182 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | 1207 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1183 | ir_print_prefix(irp, instruction); | 1208 | ir_print_prefix(irp, instruction); |
| 1184 | switch (instruction->id) { | 1209 | switch (instruction->id) { |
| ... | @@ -1559,6 +1584,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -1559,6 +1584,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1559 | case IrInstructionIdAddImplicitReturnType: | 1584 | case IrInstructionIdAddImplicitReturnType: |
| 1560 | ir_print_add_implicit_return_type(irp, (IrInstructionAddImplicitReturnType *)instruction); | 1585 | ir_print_add_implicit_return_type(irp, (IrInstructionAddImplicitReturnType *)instruction); |
| 1561 | break; | 1586 | break; |
| 1587 | case IrInstructionIdMergeErrRetTraces: | ||
| 1588 | ir_print_merge_err_ret_traces(irp, (IrInstructionMergeErrRetTraces *)instruction); | ||
| 1589 | break; | ||
| 1590 | case IrInstructionIdMarkErrRetTracePtr: | ||
| 1591 | ir_print_mark_err_ret_trace_ptr(irp, (IrInstructionMarkErrRetTracePtr *)instruction); | ||
| 1592 | break; | ||
| 1562 | } | 1593 | } |
| 1563 | fprintf(irp->f, "\n"); | 1594 | fprintf(irp->f, "\n"); |
| 1564 | } | 1595 | } |
test/cases/coroutines.zig+35| ... | @@ -1,4 +1,5 @@ | ... | @@ -1,4 +1,5 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | ||
| 2 | const assert = std.debug.assert; | 3 | const assert = std.debug.assert; |
| 3 | 4 | ||
| 4 | var x: i32 = 1; | 5 | var x: i32 = 1; |
| ... | @@ -189,3 +190,37 @@ async fn failing() !void { | ... | @@ -189,3 +190,37 @@ async fn failing() !void { |
| 189 | suspend; | 190 | suspend; |
| 190 | return error.Fail; | 191 | return error.Fail; |
| 191 | } | 192 | } |
| 193 | |||
| 194 | test "error return trace across suspend points - early return" { | ||
| 195 | const p = nonFailing(); | ||
| 196 | resume p; | ||
| 197 | const p2 = try async<std.debug.global_allocator> printTrace(p); | ||
| 198 | cancel p2; | ||
| 199 | } | ||
| 200 | |||
| 201 | test "error return trace across suspend points - async return" { | ||
| 202 | const p = nonFailing(); | ||
| 203 | const p2 = try async<std.debug.global_allocator> printTrace(p); | ||
| 204 | resume p; | ||
| 205 | cancel p2; | ||
| 206 | } | ||
| 207 | |||
| 208 | fn nonFailing() promise->error!void { | ||
| 209 | return async<std.debug.global_allocator> suspendThenFail() catch unreachable; | ||
| 210 | } | ||
| 211 | |||
| 212 | async fn suspendThenFail() error!void { | ||
| 213 | suspend; | ||
| 214 | return error.Fail; | ||
| 215 | } | ||
| 216 | |||
| 217 | async fn printTrace(p: promise->error!void) void { | ||
| 218 | (await p) catch |e| { | ||
| 219 | std.debug.assert(e == error.Fail); | ||
| 220 | if (@errorReturnTrace()) |trace| { | ||
| 221 | assert(trace.index == 1); | ||
| 222 | } else if (builtin.mode != builtin.Mode.ReleaseFast) { | ||
| 223 | @panic("expected return trace"); | ||
| 224 | } | ||
| 225 | }; | ||
| 226 | } |