| author | |
| committer | |
| log | ca2aa4880f468f12bcbe3d6cd315729dd361eff2 |
| tree | 92bdee1022a3497b2f048e450b23d4e585a649f8 |
| parent | 4b8325f3815c7fa774bb06ef5d190f039723222b |
| parent | 10541c8fc88875cb51df0a5fdeda20847133e676 |
18 files changed, 851 insertions(+), 212 deletions(-)
README.md+1-1| ... | ... | @@ -55,7 +55,7 @@ brew install cmake llvm@8 |
| 55 | 55 | brew outdated llvm@8 || brew upgrade llvm@8 |
| 56 | 56 | mkdir build |
| 57 | 57 | cd build |
| 58 | cmake .. -DCMAKE_PREFIX_PATH=/usr/local/Cellar/llvm/8.0.0_1 | |
| 58 | cmake .. -DCMAKE_PREFIX_PATH=$(brew --prefix llvm) | |
| 59 | 59 | make install |
| 60 | 60 | ``` |
| 61 | 61 |
src/all_types.hpp+23| ... | ... | @@ -36,6 +36,7 @@ struct IrInstruction; |
| 36 | 36 | struct IrInstructionCast; |
| 37 | 37 | struct IrInstructionAllocaGen; |
| 38 | 38 | struct IrInstructionCallGen; |
| 39 | struct IrInstructionAwaitGen; | |
| 39 | 40 | struct IrBasicBlock; |
| 40 | 41 | struct ScopeDecls; |
| 41 | 42 | struct ZigWindowsSDK; |
| ... | ... | @@ -308,10 +309,12 @@ struct ConstGlobalRefs { |
| 308 | 309 | enum LazyValueId { |
| 309 | 310 | LazyValueIdInvalid, |
| 310 | 311 | LazyValueIdAlignOf, |
| 312 | LazyValueIdSizeOf, | |
| 311 | 313 | LazyValueIdPtrType, |
| 312 | 314 | LazyValueIdOptType, |
| 313 | 315 | LazyValueIdSliceType, |
| 314 | 316 | LazyValueIdFnType, |
| 317 | LazyValueIdErrUnionType, | |
| 315 | 318 | }; |
| 316 | 319 | |
| 317 | 320 | struct LazyValue { |
| ... | ... | @@ -325,6 +328,13 @@ struct LazyValueAlignOf { |
| 325 | 328 | IrInstruction *target_type; |
| 326 | 329 | }; |
| 327 | 330 | |
| 331 | struct LazyValueSizeOf { | |
| 332 | LazyValue base; | |
| 333 | ||
| 334 | IrAnalyze *ira; | |
| 335 | IrInstruction *target_type; | |
| 336 | }; | |
| 337 | ||
| 328 | 338 | struct LazyValueSliceType { |
| 329 | 339 | LazyValue base; |
| 330 | 340 | |
| ... | ... | @@ -372,6 +382,14 @@ struct LazyValueFnType { |
| 372 | 382 | bool is_generic; |
| 373 | 383 | }; |
| 374 | 384 | |
| 385 | struct LazyValueErrUnionType { | |
| 386 | LazyValue base; | |
| 387 | ||
| 388 | IrAnalyze *ira; | |
| 389 | IrInstruction *err_set_type; | |
| 390 | IrInstruction *payload_type; | |
| 391 | }; | |
| 392 | ||
| 375 | 393 | struct ConstExprValue { |
| 376 | 394 | ZigType *type; |
| 377 | 395 | ConstValSpecial special; |
| ... | ... | @@ -1205,6 +1223,7 @@ struct ZigTypeStruct { |
| 1205 | 1223 | HashMap<Buf *, TypeStructField *, buf_hash, buf_eql_buf> fields_by_name; |
| 1206 | 1224 | RootStruct *root_struct; |
| 1207 | 1225 | uint32_t *host_int_bytes; // available for packed structs, indexed by gen_index |
| 1226 | size_t llvm_full_type_queue_index; | |
| 1208 | 1227 | |
| 1209 | 1228 | uint32_t src_field_count; |
| 1210 | 1229 | uint32_t gen_field_count; |
| ... | ... | @@ -1468,6 +1487,7 @@ struct ZigFn { |
| 1468 | 1487 | AstNode **param_source_nodes; |
| 1469 | 1488 | Buf **param_names; |
| 1470 | 1489 | IrInstruction *err_code_spill; |
| 1490 | AstNode *assumed_non_async; | |
| 1471 | 1491 | |
| 1472 | 1492 | AstNode *fn_no_inline_set_node; |
| 1473 | 1493 | AstNode *fn_static_eval_set_node; |
| ... | ... | @@ -1485,6 +1505,7 @@ struct ZigFn { |
| 1485 | 1505 | |
| 1486 | 1506 | ZigList<GlobalExport> export_list; |
| 1487 | 1507 | ZigList<IrInstructionCallGen *> call_list; |
| 1508 | ZigList<IrInstructionAwaitGen *> await_list; | |
| 1488 | 1509 | |
| 1489 | 1510 | LLVMValueRef valgrind_client_request_array; |
| 1490 | 1511 | |
| ... | ... | @@ -1852,6 +1873,7 @@ struct CodeGen { |
| 1852 | 1873 | ZigList<ErrorTableEntry *> errors_by_index; |
| 1853 | 1874 | ZigList<CacheHash *> caches_to_release; |
| 1854 | 1875 | size_t largest_err_name_len; |
| 1876 | ZigList<ZigType *> type_resolve_stack; | |
| 1855 | 1877 | |
| 1856 | 1878 | ZigPackage *std_package; |
| 1857 | 1879 | ZigPackage *panic_package; |
| ... | ... | @@ -3698,6 +3720,7 @@ struct IrInstructionAwaitGen { |
| 3698 | 3720 | |
| 3699 | 3721 | IrInstruction *frame; |
| 3700 | 3722 | IrInstruction *result_loc; |
| 3723 | ZigFn *target_fn; | |
| 3701 | 3724 | }; |
| 3702 | 3725 | |
| 3703 | 3726 | struct IrInstructionResume { |
src/analyze.cpp+194-43| ... | ... | @@ -31,6 +31,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry); |
| 31 | 31 | static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status); |
| 32 | 32 | static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope); |
| 33 | 33 | static void resolve_use_decl(CodeGen *g, TldUsingNamespace *tld_using_namespace, ScopeDecls *dest_decls_scope); |
| 34 | static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame); | |
| 34 | 35 | |
| 35 | 36 | // nullptr means not analyzed yet; this one means currently being analyzed |
| 36 | 37 | static const AstNode *inferred_async_checking = reinterpret_cast<AstNode *>(0x1); |
| ... | ... | @@ -973,7 +974,7 @@ ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, Zig |
| 973 | 974 | nullptr, nullptr, node, type_name, nullptr, nullptr, undef); |
| 974 | 975 | } |
| 975 | 976 | |
| 976 | static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, ZigType *parent_type, | |
| 977 | Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, ZigType *parent_type, | |
| 977 | 978 | ConstExprValue *parent_type_val, bool *is_zero_bits) |
| 978 | 979 | { |
| 979 | 980 | Error err; |
| ... | ... | @@ -997,6 +998,7 @@ static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, Zi |
| 997 | 998 | switch (type_val->data.x_lazy->id) { |
| 998 | 999 | case LazyValueIdInvalid: |
| 999 | 1000 | case LazyValueIdAlignOf: |
| 1001 | case LazyValueIdSizeOf: | |
| 1000 | 1002 | zig_unreachable(); |
| 1001 | 1003 | case LazyValueIdPtrType: { |
| 1002 | 1004 | LazyValuePtrType *lazy_ptr_type = reinterpret_cast<LazyValuePtrType *>(type_val->data.x_lazy); |
| ... | ... | @@ -1015,6 +1017,7 @@ static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, Zi |
| 1015 | 1017 | } |
| 1016 | 1018 | case LazyValueIdOptType: |
| 1017 | 1019 | case LazyValueIdSliceType: |
| 1020 | case LazyValueIdErrUnionType: | |
| 1018 | 1021 | *is_zero_bits = false; |
| 1019 | 1022 | return ErrorNone; |
| 1020 | 1023 | case LazyValueIdFnType: { |
| ... | ... | @@ -1035,11 +1038,13 @@ Error type_val_resolve_is_opaque_type(CodeGen *g, ConstExprValue *type_val, bool |
| 1035 | 1038 | switch (type_val->data.x_lazy->id) { |
| 1036 | 1039 | case LazyValueIdInvalid: |
| 1037 | 1040 | case LazyValueIdAlignOf: |
| 1041 | case LazyValueIdSizeOf: | |
| 1038 | 1042 | zig_unreachable(); |
| 1039 | 1043 | case LazyValueIdSliceType: |
| 1040 | 1044 | case LazyValueIdPtrType: |
| 1041 | 1045 | case LazyValueIdFnType: |
| 1042 | 1046 | case LazyValueIdOptType: |
| 1047 | case LazyValueIdErrUnionType: | |
| 1043 | 1048 | *is_opaque_type = false; |
| 1044 | 1049 | return ErrorNone; |
| 1045 | 1050 | } |
| ... | ... | @@ -1053,6 +1058,7 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue |
| 1053 | 1058 | switch (type_val->data.x_lazy->id) { |
| 1054 | 1059 | case LazyValueIdInvalid: |
| 1055 | 1060 | case LazyValueIdAlignOf: |
| 1061 | case LazyValueIdSizeOf: | |
| 1056 | 1062 | zig_unreachable(); |
| 1057 | 1063 | case LazyValueIdSliceType: { |
| 1058 | 1064 | LazyValueSliceType *lazy_slice_type = reinterpret_cast<LazyValueSliceType *>(type_val->data.x_lazy); |
| ... | ... | @@ -1094,18 +1100,21 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue |
| 1094 | 1100 | } |
| 1095 | 1101 | return ReqCompTimeNo; |
| 1096 | 1102 | } |
| 1103 | case LazyValueIdErrUnionType: { | |
| 1104 | LazyValueErrUnionType *lazy_err_union_type = | |
| 1105 | reinterpret_cast<LazyValueErrUnionType *>(type_val->data.x_lazy); | |
| 1106 | return type_val_resolve_requires_comptime(g, &lazy_err_union_type->payload_type->value); | |
| 1107 | } | |
| 1097 | 1108 | } |
| 1098 | 1109 | zig_unreachable(); |
| 1099 | 1110 | } |
| 1100 | 1111 | |
| 1101 | static Error type_val_resolve_abi_size(CodeGen *g, AstNode *source_node, ConstExprValue *type_val, | |
| 1112 | Error type_val_resolve_abi_size(CodeGen *g, AstNode *source_node, ConstExprValue *type_val, | |
| 1102 | 1113 | size_t *abi_size, size_t *size_in_bits) |
| 1103 | 1114 | { |
| 1104 | 1115 | Error err; |
| 1105 | if (type_val->data.x_lazy->id == LazyValueIdOptType) { | |
| 1106 | if ((err = ir_resolve_lazy(g, source_node, type_val))) | |
| 1107 | return err; | |
| 1108 | } | |
| 1116 | ||
| 1117 | start_over: | |
| 1109 | 1118 | if (type_val->special != ConstValSpecialLazy) { |
| 1110 | 1119 | assert(type_val->special == ConstValSpecialStatic); |
| 1111 | 1120 | ZigType *ty = type_val->data.x_type; |
| ... | ... | @@ -1118,18 +1127,51 @@ static Error type_val_resolve_abi_size(CodeGen *g, AstNode *source_node, ConstEx |
| 1118 | 1127 | switch (type_val->data.x_lazy->id) { |
| 1119 | 1128 | case LazyValueIdInvalid: |
| 1120 | 1129 | case LazyValueIdAlignOf: |
| 1130 | case LazyValueIdSizeOf: | |
| 1121 | 1131 | zig_unreachable(); |
| 1122 | case LazyValueIdSliceType: | |
| 1123 | *abi_size = g->builtin_types.entry_usize->abi_size * 2; | |
| 1124 | *size_in_bits = g->builtin_types.entry_usize->size_in_bits * 2; | |
| 1132 | case LazyValueIdSliceType: { | |
| 1133 | LazyValueSliceType *lazy_slice_type = reinterpret_cast<LazyValueSliceType *>(type_val->data.x_lazy); | |
| 1134 | bool is_zero_bits; | |
| 1135 | if ((err = type_val_resolve_zero_bits(g, &lazy_slice_type->elem_type->value, nullptr, | |
| 1136 | nullptr, &is_zero_bits))) | |
| 1137 | { | |
| 1138 | return err; | |
| 1139 | } | |
| 1140 | if (is_zero_bits) { | |
| 1141 | *abi_size = g->builtin_types.entry_usize->abi_size; | |
| 1142 | *size_in_bits = g->builtin_types.entry_usize->size_in_bits; | |
| 1143 | } else { | |
| 1144 | *abi_size = g->builtin_types.entry_usize->abi_size * 2; | |
| 1145 | *size_in_bits = g->builtin_types.entry_usize->size_in_bits * 2; | |
| 1146 | } | |
| 1125 | 1147 | return ErrorNone; |
| 1126 | case LazyValueIdPtrType: | |
| 1148 | } | |
| 1149 | case LazyValueIdPtrType: { | |
| 1150 | LazyValuePtrType *lazy_ptr_type = reinterpret_cast<LazyValuePtrType *>(type_val->data.x_lazy); | |
| 1151 | bool is_zero_bits; | |
| 1152 | if ((err = type_val_resolve_zero_bits(g, &lazy_ptr_type->elem_type->value, nullptr, | |
| 1153 | nullptr, &is_zero_bits))) | |
| 1154 | { | |
| 1155 | return err; | |
| 1156 | } | |
| 1157 | if (is_zero_bits) { | |
| 1158 | *abi_size = 0; | |
| 1159 | *size_in_bits = 0; | |
| 1160 | } else { | |
| 1161 | *abi_size = g->builtin_types.entry_usize->abi_size; | |
| 1162 | *size_in_bits = g->builtin_types.entry_usize->size_in_bits; | |
| 1163 | } | |
| 1164 | return ErrorNone; | |
| 1165 | } | |
| 1127 | 1166 | case LazyValueIdFnType: |
| 1128 | 1167 | *abi_size = g->builtin_types.entry_usize->abi_size; |
| 1129 | 1168 | *size_in_bits = g->builtin_types.entry_usize->size_in_bits; |
| 1130 | 1169 | return ErrorNone; |
| 1131 | 1170 | case LazyValueIdOptType: |
| 1132 | zig_unreachable(); | |
| 1171 | case LazyValueIdErrUnionType: | |
| 1172 | if ((err = ir_resolve_lazy(g, source_node, type_val))) | |
| 1173 | return err; | |
| 1174 | goto start_over; | |
| 1133 | 1175 | } |
| 1134 | 1176 | zig_unreachable(); |
| 1135 | 1177 | } |
| ... | ... | @@ -1151,6 +1193,7 @@ Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, uint32_t |
| 1151 | 1193 | switch (type_val->data.x_lazy->id) { |
| 1152 | 1194 | case LazyValueIdInvalid: |
| 1153 | 1195 | case LazyValueIdAlignOf: |
| 1196 | case LazyValueIdSizeOf: | |
| 1154 | 1197 | zig_unreachable(); |
| 1155 | 1198 | case LazyValueIdSliceType: |
| 1156 | 1199 | case LazyValueIdPtrType: |
| ... | ... | @@ -1161,6 +1204,19 @@ Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, uint32_t |
| 1161 | 1204 | LazyValueOptType *lazy_opt_type = reinterpret_cast<LazyValueOptType *>(type_val->data.x_lazy); |
| 1162 | 1205 | return type_val_resolve_abi_align(g, &lazy_opt_type->payload_type->value, abi_align); |
| 1163 | 1206 | } |
| 1207 | case LazyValueIdErrUnionType: { | |
| 1208 | LazyValueErrUnionType *lazy_err_union_type = | |
| 1209 | reinterpret_cast<LazyValueErrUnionType *>(type_val->data.x_lazy); | |
| 1210 | uint32_t payload_abi_align; | |
| 1211 | if ((err = type_val_resolve_abi_align(g, &lazy_err_union_type->payload_type->value, | |
| 1212 | &payload_abi_align))) | |
| 1213 | { | |
| 1214 | return err; | |
| 1215 | } | |
| 1216 | *abi_align = (payload_abi_align > g->err_tag_type->abi_align) ? | |
| 1217 | payload_abi_align : g->err_tag_type->abi_align; | |
| 1218 | return ErrorNone; | |
| 1219 | } | |
| 1164 | 1220 | } |
| 1165 | 1221 | zig_unreachable(); |
| 1166 | 1222 | } |
| ... | ... | @@ -1172,6 +1228,7 @@ static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, Cons |
| 1172 | 1228 | switch (type_val->data.x_lazy->id) { |
| 1173 | 1229 | case LazyValueIdInvalid: |
| 1174 | 1230 | case LazyValueIdAlignOf: |
| 1231 | case LazyValueIdSizeOf: | |
| 1175 | 1232 | zig_unreachable(); |
| 1176 | 1233 | case LazyValueIdSliceType: // it has the len field |
| 1177 | 1234 | case LazyValueIdOptType: // it has the optional bit |
| ... | ... | @@ -1189,6 +1246,18 @@ static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, Cons |
| 1189 | 1246 | return OnePossibleValueNo; |
| 1190 | 1247 | } |
| 1191 | 1248 | } |
| 1249 | case LazyValueIdErrUnionType: { | |
| 1250 | LazyValueErrUnionType *lazy_err_union_type = | |
| 1251 | reinterpret_cast<LazyValueErrUnionType *>(type_val->data.x_lazy); | |
| 1252 | switch (type_val_resolve_has_one_possible_value(g, &lazy_err_union_type->err_set_type->value)) { | |
| 1253 | case OnePossibleValueInvalid: | |
| 1254 | return OnePossibleValueInvalid; | |
| 1255 | case OnePossibleValueNo: | |
| 1256 | return OnePossibleValueNo; | |
| 1257 | case OnePossibleValueYes: | |
| 1258 | return type_val_resolve_has_one_possible_value(g, &lazy_err_union_type->payload_type->value); | |
| 1259 | } | |
| 1260 | } | |
| 1192 | 1261 | } |
| 1193 | 1262 | zig_unreachable(); |
| 1194 | 1263 | } |
| ... | ... | @@ -4105,8 +4174,14 @@ static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) { |
| 4105 | 4174 | assert(fn->inferred_async_node != inferred_async_checking); |
| 4106 | 4175 | assert(fn->inferred_async_node != inferred_async_none); |
| 4107 | 4176 | if (fn->inferred_async_fn != nullptr) { |
| 4108 | ErrorMsg *new_msg = add_error_note(g, msg, fn->inferred_async_node, | |
| 4109 | buf_sprintf("async function call here")); | |
| 4177 | ErrorMsg *new_msg; | |
| 4178 | if (fn->inferred_async_node->type == NodeTypeAwaitExpr) { | |
| 4179 | new_msg = add_error_note(g, msg, fn->inferred_async_node, | |
| 4180 | buf_create_from_str("await here is a suspend point")); | |
| 4181 | } else { | |
| 4182 | new_msg = add_error_note(g, msg, fn->inferred_async_node, | |
| 4183 | buf_sprintf("async function call here")); | |
| 4184 | } | |
| 4110 | 4185 | return add_async_error_notes(g, new_msg, fn->inferred_async_fn); |
| 4111 | 4186 | } else if (fn->inferred_async_node->type == NodeTypeFnProto) { |
| 4112 | 4187 | add_error_note(g, msg, fn->inferred_async_node, |
| ... | ... | @@ -4116,7 +4191,7 @@ static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) { |
| 4116 | 4191 | buf_sprintf("suspends here")); |
| 4117 | 4192 | } else if (fn->inferred_async_node->type == NodeTypeAwaitExpr) { |
| 4118 | 4193 | add_error_note(g, msg, fn->inferred_async_node, |
| 4119 | buf_sprintf("await is a suspend point")); | |
| 4194 | buf_sprintf("await here is a suspend point")); | |
| 4120 | 4195 | } else if (fn->inferred_async_node->type == NodeTypeFnCallExpr && |
| 4121 | 4196 | fn->inferred_async_node->data.fn_call_expr.is_builtin) |
| 4122 | 4197 | { |
| ... | ... | @@ -4128,6 +4203,64 @@ static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) { |
| 4128 | 4203 | } |
| 4129 | 4204 | } |
| 4130 | 4205 | |
| 4206 | // ErrorNone - not async | |
| 4207 | // ErrorIsAsync - yes async | |
| 4208 | // ErrorSemanticAnalyzeFail - compile error emitted result is invalid | |
| 4209 | static Error analyze_callee_async(CodeGen *g, ZigFn *fn, ZigFn *callee, AstNode *call_node, | |
| 4210 | bool must_not_be_async) | |
| 4211 | { | |
| 4212 | if (callee->type_entry->data.fn.fn_type_id.cc != CallingConventionUnspecified) | |
| 4213 | return ErrorNone; | |
| 4214 | if (callee->anal_state == FnAnalStateReady) { | |
| 4215 | analyze_fn_body(g, callee); | |
| 4216 | if (callee->anal_state == FnAnalStateInvalid) { | |
| 4217 | return ErrorSemanticAnalyzeFail; | |
| 4218 | } | |
| 4219 | } | |
| 4220 | bool callee_is_async; | |
| 4221 | if (callee->anal_state == FnAnalStateComplete) { | |
| 4222 | analyze_fn_async(g, callee, true); | |
| 4223 | if (callee->anal_state == FnAnalStateInvalid) { | |
| 4224 | return ErrorSemanticAnalyzeFail; | |
| 4225 | } | |
| 4226 | callee_is_async = fn_is_async(callee); | |
| 4227 | } else { | |
| 4228 | // If it's already been determined, use that value. Otherwise | |
| 4229 | // assume non-async, emit an error later if it turned out to be async. | |
| 4230 | if (callee->inferred_async_node == nullptr || | |
| 4231 | callee->inferred_async_node == inferred_async_checking) | |
| 4232 | { | |
| 4233 | callee->assumed_non_async = call_node; | |
| 4234 | callee_is_async = false; | |
| 4235 | } else { | |
| 4236 | callee_is_async = callee->inferred_async_node != inferred_async_none; | |
| 4237 | } | |
| 4238 | } | |
| 4239 | if (callee_is_async) { | |
| 4240 | fn->inferred_async_node = call_node; | |
| 4241 | fn->inferred_async_fn = callee; | |
| 4242 | if (must_not_be_async) { | |
| 4243 | ErrorMsg *msg = add_node_error(g, fn->proto_node, | |
| 4244 | buf_sprintf("function with calling convention '%s' cannot be async", | |
| 4245 | calling_convention_name(fn->type_entry->data.fn.fn_type_id.cc))); | |
| 4246 | add_async_error_notes(g, msg, fn); | |
| 4247 | return ErrorSemanticAnalyzeFail; | |
| 4248 | } | |
| 4249 | if (fn->assumed_non_async != nullptr) { | |
| 4250 | ErrorMsg *msg = add_node_error(g, fn->proto_node, | |
| 4251 | buf_sprintf("unable to infer whether '%s' should be async", | |
| 4252 | buf_ptr(&fn->symbol_name))); | |
| 4253 | add_error_note(g, msg, fn->assumed_non_async, | |
| 4254 | buf_sprintf("assumed to be non-async here")); | |
| 4255 | add_async_error_notes(g, msg, fn); | |
| 4256 | fn->anal_state = FnAnalStateInvalid; | |
| 4257 | return ErrorSemanticAnalyzeFail; | |
| 4258 | } | |
| 4259 | return ErrorIsAsync; | |
| 4260 | } | |
| 4261 | return ErrorNone; | |
| 4262 | } | |
| 4263 | ||
| 4131 | 4264 | // This function resolves functions being inferred async. |
| 4132 | 4265 | static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) { |
| 4133 | 4266 | if (fn->inferred_async_node == inferred_async_checking) { |
| ... | ... | @@ -4154,42 +4287,40 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) { |
| 4154 | 4287 | |
| 4155 | 4288 | for (size_t i = 0; i < fn->call_list.length; i += 1) { |
| 4156 | 4289 | IrInstructionCallGen *call = fn->call_list.at(i); |
| 4157 | ZigFn *callee = call->fn_entry; | |
| 4158 | if (callee == nullptr) { | |
| 4290 | if (call->fn_entry == nullptr) { | |
| 4159 | 4291 | // TODO function pointer call here, could be anything |
| 4160 | 4292 | continue; |
| 4161 | 4293 | } |
| 4162 | ||
| 4163 | if (callee->type_entry->data.fn.fn_type_id.cc != CallingConventionUnspecified) | |
| 4164 | continue; | |
| 4165 | if (callee->anal_state == FnAnalStateReady) { | |
| 4166 | analyze_fn_body(g, callee); | |
| 4167 | if (callee->anal_state == FnAnalStateInvalid) { | |
| 4294 | switch (analyze_callee_async(g, fn, call->fn_entry, call->base.source_node, must_not_be_async)) { | |
| 4295 | case ErrorSemanticAnalyzeFail: | |
| 4168 | 4296 | fn->anal_state = FnAnalStateInvalid; |
| 4169 | 4297 | return; |
| 4170 | } | |
| 4171 | } | |
| 4172 | assert(callee->anal_state == FnAnalStateComplete); | |
| 4173 | analyze_fn_async(g, callee, true); | |
| 4174 | if (callee->anal_state == FnAnalStateInvalid) { | |
| 4175 | fn->anal_state = FnAnalStateInvalid; | |
| 4176 | return; | |
| 4298 | case ErrorNone: | |
| 4299 | continue; | |
| 4300 | case ErrorIsAsync: | |
| 4301 | if (resolve_frame) { | |
| 4302 | resolve_async_fn_frame(g, fn); | |
| 4303 | } | |
| 4304 | return; | |
| 4305 | default: | |
| 4306 | zig_unreachable(); | |
| 4177 | 4307 | } |
| 4178 | if (fn_is_async(callee)) { | |
| 4179 | fn->inferred_async_node = call->base.source_node; | |
| 4180 | fn->inferred_async_fn = callee; | |
| 4181 | if (must_not_be_async) { | |
| 4182 | ErrorMsg *msg = add_node_error(g, fn->proto_node, | |
| 4183 | buf_sprintf("function with calling convention '%s' cannot be async", | |
| 4184 | calling_convention_name(fn->type_entry->data.fn.fn_type_id.cc))); | |
| 4185 | add_async_error_notes(g, msg, fn); | |
| 4308 | } | |
| 4309 | for (size_t i = 0; i < fn->await_list.length; i += 1) { | |
| 4310 | IrInstructionAwaitGen *await = fn->await_list.at(i); | |
| 4311 | switch (analyze_callee_async(g, fn, await->target_fn, await->base.source_node, must_not_be_async)) { | |
| 4312 | case ErrorSemanticAnalyzeFail: | |
| 4186 | 4313 | fn->anal_state = FnAnalStateInvalid; |
| 4187 | 4314 | return; |
| 4188 | } | |
| 4189 | if (resolve_frame) { | |
| 4190 | resolve_async_fn_frame(g, fn); | |
| 4191 | } | |
| 4192 | return; | |
| 4315 | case ErrorNone: | |
| 4316 | continue; | |
| 4317 | case ErrorIsAsync: | |
| 4318 | if (resolve_frame) { | |
| 4319 | resolve_async_fn_frame(g, fn); | |
| 4320 | } | |
| 4321 | return; | |
| 4322 | default: | |
| 4323 | zig_unreachable(); | |
| 4193 | 4324 | } |
| 4194 | 4325 | } |
| 4195 | 4326 | fn->inferred_async_node = inferred_async_none; |
| ... | ... | @@ -4447,6 +4578,8 @@ void semantic_analyze(CodeGen *g) { |
| 4447 | 4578 | ZigFn *fn = g->fn_defs.at(g->fn_defs_index); |
| 4448 | 4579 | g->trace_err = nullptr; |
| 4449 | 4580 | analyze_fn_async(g, fn, true); |
| 4581 | if (fn->anal_state == FnAnalStateInvalid) | |
| 4582 | continue; | |
| 4450 | 4583 | if (fn_is_async(fn) && fn->non_async_node != nullptr) { |
| 4451 | 4584 | ErrorMsg *msg = add_node_error(g, fn->proto_node, |
| 4452 | 4585 | buf_sprintf("'%s' cannot be async", buf_ptr(&fn->symbol_name))); |
| ... | ... | @@ -5599,6 +5732,11 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { |
| 5599 | 5732 | return ErrorSemanticAnalyzeFail; |
| 5600 | 5733 | } |
| 5601 | 5734 | analyze_fn_async(g, callee, true); |
| 5735 | if (callee->inferred_async_node == inferred_async_checking) { | |
| 5736 | assert(g->errors.length != 0); | |
| 5737 | frame_type->data.frame.locals_struct = g->builtin_types.entry_invalid; | |
| 5738 | return ErrorSemanticAnalyzeFail; | |
| 5739 | } | |
| 5602 | 5740 | if (!fn_is_async(callee)) |
| 5603 | 5741 | continue; |
| 5604 | 5742 | |
| ... | ... | @@ -7238,7 +7376,13 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS |
| 7238 | 7376 | di_scope, di_file, line); |
| 7239 | 7377 | |
| 7240 | 7378 | struct_type->data.structure.resolve_status = ResolveStatusLLVMFwdDecl; |
| 7241 | if (ResolveStatusLLVMFwdDecl >= wanted_resolve_status) return; | |
| 7379 | if (ResolveStatusLLVMFwdDecl >= wanted_resolve_status) { | |
| 7380 | struct_type->data.structure.llvm_full_type_queue_index = g->type_resolve_stack.length; | |
| 7381 | g->type_resolve_stack.append(struct_type); | |
| 7382 | return; | |
| 7383 | } else { | |
| 7384 | struct_type->data.structure.llvm_full_type_queue_index = SIZE_MAX; | |
| 7385 | } | |
| 7242 | 7386 | } |
| 7243 | 7387 | |
| 7244 | 7388 | size_t field_count = struct_type->data.structure.src_field_count; |
| ... | ... | @@ -7442,6 +7586,13 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS |
| 7442 | 7586 | ZigLLVMReplaceTemporary(g->dbuilder, struct_type->llvm_di_type, replacement_di_type); |
| 7443 | 7587 | struct_type->llvm_di_type = replacement_di_type; |
| 7444 | 7588 | struct_type->data.structure.resolve_status = ResolveStatusLLVMFull; |
| 7589 | if (struct_type->data.structure.llvm_full_type_queue_index != SIZE_MAX) { | |
| 7590 | ZigType *last = g->type_resolve_stack.last(); | |
| 7591 | assert(last->id == ZigTypeIdStruct); | |
| 7592 | last->data.structure.llvm_full_type_queue_index = struct_type->data.structure.llvm_full_type_queue_index; | |
| 7593 | g->type_resolve_stack.swap_remove(struct_type->data.structure.llvm_full_type_queue_index); | |
| 7594 | struct_type->data.structure.llvm_full_type_queue_index = SIZE_MAX; | |
| 7595 | } | |
| 7445 | 7596 | } |
| 7446 | 7597 | |
| 7447 | 7598 | static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type, ResolveStatus wanted_resolve_status) { |
src/analyze.hpp+4| ... | ... | @@ -247,6 +247,10 @@ void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn); |
| 247 | 247 | bool fn_is_async(ZigFn *fn); |
| 248 | 248 | |
| 249 | 249 | Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, uint32_t *abi_align); |
| 250 | Error type_val_resolve_abi_size(CodeGen *g, AstNode *source_node, ConstExprValue *type_val, | |
| 251 | size_t *abi_size, size_t *size_in_bits); | |
| 252 | Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, ZigType *parent_type, | |
| 253 | ConstExprValue *parent_type_val, bool *is_zero_bits); | |
| 250 | 254 | ZigType *resolve_union_field_type(CodeGen *g, TypeUnionField *union_field); |
| 251 | 255 | ZigType *resolve_struct_field_type(CodeGen *g, TypeStructField *struct_field); |
| 252 | 256 |
src/codegen.cpp+82-35| ... | ... | @@ -3052,8 +3052,10 @@ static LLVMValueRef ir_render_ptr_of_array_to_slice(CodeGen *g, IrExecutable *ex |
| 3052 | 3052 | IrInstructionPtrOfArrayToSlice *instruction) |
| 3053 | 3053 | { |
| 3054 | 3054 | ZigType *actual_type = instruction->operand->value.type; |
| 3055 | LLVMValueRef expr_val = ir_llvm_value(g, instruction->operand); | |
| 3056 | assert(expr_val); | |
| 3055 | ZigType *slice_type = instruction->base.value.type; | |
| 3056 | ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index].type_entry; | |
| 3057 | size_t ptr_index = slice_type->data.structure.fields[slice_ptr_index].gen_index; | |
| 3058 | size_t len_index = slice_type->data.structure.fields[slice_len_index].gen_index; | |
| 3057 | 3059 | |
| 3058 | 3060 | LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); |
| 3059 | 3061 | |
| ... | ... | @@ -3061,15 +3063,21 @@ static LLVMValueRef ir_render_ptr_of_array_to_slice(CodeGen *g, IrExecutable *ex |
| 3061 | 3063 | ZigType *array_type = actual_type->data.pointer.child_type; |
| 3062 | 3064 | assert(array_type->id == ZigTypeIdArray); |
| 3063 | 3065 | |
| 3064 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, result_loc, slice_ptr_index, ""); | |
| 3065 | LLVMValueRef indices[] = { | |
| 3066 | LLVMConstNull(g->builtin_types.entry_usize->llvm_type), | |
| 3067 | LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 0, false), | |
| 3068 | }; | |
| 3069 | LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, expr_val, indices, 2, ""); | |
| 3070 | gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); | |
| 3066 | if (type_has_bits(actual_type)) { | |
| 3067 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, result_loc, ptr_index, ""); | |
| 3068 | LLVMValueRef indices[] = { | |
| 3069 | LLVMConstNull(g->builtin_types.entry_usize->llvm_type), | |
| 3070 | LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 0, false), | |
| 3071 | }; | |
| 3072 | LLVMValueRef expr_val = ir_llvm_value(g, instruction->operand); | |
| 3073 | LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, expr_val, indices, 2, ""); | |
| 3074 | gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); | |
| 3075 | } else if (ir_want_runtime_safety(g, &instruction->base)) { | |
| 3076 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, result_loc, ptr_index, ""); | |
| 3077 | gen_undef_init(g, slice_ptr_type->abi_align, slice_ptr_type, ptr_field_ptr); | |
| 3078 | } | |
| 3071 | 3079 | |
| 3072 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, result_loc, slice_len_index, ""); | |
| 3080 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, result_loc, len_index, ""); | |
| 3073 | 3081 | LLVMValueRef len_value = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, |
| 3074 | 3082 | array_type->data.array.len, false); |
| 3075 | 3083 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); |
| ... | ... | @@ -3916,7 +3924,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3916 | 3924 | LLVMBuildStore(g->builder, awaiter_init_val, awaiter_ptr); |
| 3917 | 3925 | |
| 3918 | 3926 | if (ret_has_bits) { |
| 3919 | LLVMValueRef ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, ""); | |
| 3927 | ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, ""); | |
| 3920 | 3928 | LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start, ""); |
| 3921 | 3929 | LLVMBuildStore(g->builder, ret_ptr, ret_ptr_ptr); |
| 3922 | 3930 | |
| ... | ... | @@ -4059,6 +4067,9 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 4059 | 4067 | LLVMValueRef store_instr = LLVMBuildStore(g->builder, result, result_loc); |
| 4060 | 4068 | LLVMSetAlignment(store_instr, get_ptr_align(g, instruction->result_loc->value.type)); |
| 4061 | 4069 | return result_loc; |
| 4070 | } else if (!callee_is_async && instruction->is_async) { | |
| 4071 | LLVMBuildStore(g->builder, result, ret_ptr); | |
| 4072 | return result_loc; | |
| 4062 | 4073 | } else { |
| 4063 | 4074 | return result; |
| 4064 | 4075 | } |
| ... | ... | @@ -5490,6 +5501,44 @@ static LLVMValueRef ir_render_suspend_finish(CodeGen *g, IrExecutable *executabl |
| 5490 | 5501 | return nullptr; |
| 5491 | 5502 | } |
| 5492 | 5503 | |
| 5504 | static LLVMValueRef gen_await_early_return(CodeGen *g, IrInstruction *source_instr, | |
| 5505 | LLVMValueRef target_frame_ptr, ZigType *result_type, ZigType *ptr_result_type, | |
| 5506 | LLVMValueRef result_loc, bool non_async) | |
| 5507 | { | |
| 5508 | LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; | |
| 5509 | LLVMValueRef their_result_ptr = nullptr; | |
| 5510 | if (type_has_bits(result_type) && (non_async || result_loc != nullptr)) { | |
| 5511 | LLVMValueRef their_result_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, frame_ret_start, ""); | |
| 5512 | their_result_ptr = LLVMBuildLoad(g->builder, their_result_ptr_ptr, ""); | |
| 5513 | if (result_loc != nullptr) { | |
| 5514 | LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); | |
| 5515 | LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, result_loc, ptr_u8, ""); | |
| 5516 | LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, their_result_ptr, ptr_u8, ""); | |
| 5517 | bool is_volatile = false; | |
| 5518 | uint32_t abi_align = get_abi_alignment(g, result_type); | |
| 5519 | LLVMValueRef byte_count_val = LLVMConstInt(usize_type_ref, type_size(g, result_type), false); | |
| 5520 | ZigLLVMBuildMemCpy(g->builder, | |
| 5521 | dest_ptr_casted, abi_align, | |
| 5522 | src_ptr_casted, abi_align, byte_count_val, is_volatile); | |
| 5523 | } | |
| 5524 | } | |
| 5525 | if (codegen_fn_has_err_ret_tracing_arg(g, result_type)) { | |
| 5526 | LLVMValueRef their_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, | |
| 5527 | frame_index_trace_arg(g, result_type), ""); | |
| 5528 | LLVMValueRef src_trace_ptr = LLVMBuildLoad(g->builder, their_trace_ptr_ptr, ""); | |
| 5529 | LLVMValueRef dest_trace_ptr = get_cur_err_ret_trace_val(g, source_instr->scope); | |
| 5530 | LLVMValueRef args[] = { dest_trace_ptr, src_trace_ptr }; | |
| 5531 | ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2, | |
| 5532 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); | |
| 5533 | } | |
| 5534 | if (non_async && type_has_bits(result_type)) { | |
| 5535 | LLVMValueRef result_ptr = (result_loc == nullptr) ? their_result_ptr : result_loc; | |
| 5536 | return get_handle_value(g, result_ptr, result_type, ptr_result_type); | |
| 5537 | } else { | |
| 5538 | return nullptr; | |
| 5539 | } | |
| 5540 | } | |
| 5541 | ||
| 5493 | 5542 | static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInstructionAwaitGen *instruction) { |
| 5494 | 5543 | LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; |
| 5495 | 5544 | LLVMValueRef zero = LLVMConstNull(usize_type_ref); |
| ... | ... | @@ -5497,6 +5546,14 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInst |
| 5497 | 5546 | ZigType *result_type = instruction->base.value.type; |
| 5498 | 5547 | ZigType *ptr_result_type = get_pointer_to_type(g, result_type, true); |
| 5499 | 5548 | |
| 5549 | LLVMValueRef result_loc = (instruction->result_loc == nullptr) ? | |
| 5550 | nullptr : ir_llvm_value(g, instruction->result_loc); | |
| 5551 | ||
| 5552 | if (instruction->target_fn != nullptr && !fn_is_async(instruction->target_fn)) { | |
| 5553 | return gen_await_early_return(g, &instruction->base, target_frame_ptr, result_type, | |
| 5554 | ptr_result_type, result_loc, true); | |
| 5555 | } | |
| 5556 | ||
| 5500 | 5557 | // Prepare to be suspended |
| 5501 | 5558 | LLVMBasicBlockRef resume_bb = gen_suspend_begin(g, "AwaitResume"); |
| 5502 | 5559 | LLVMBasicBlockRef end_bb = LLVMAppendBasicBlock(g->cur_fn_val, "AwaitEnd"); |
| ... | ... | @@ -5504,9 +5561,8 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInst |
| 5504 | 5561 | // At this point resuming the function will continue from resume_bb. |
| 5505 | 5562 | // This code is as if it is running inside the suspend block. |
| 5506 | 5563 | |
| 5564 | ||
| 5507 | 5565 | // supply the awaiter return pointer |
| 5508 | LLVMValueRef result_loc = (instruction->result_loc == nullptr) ? | |
| 5509 | nullptr : ir_llvm_value(g, instruction->result_loc); | |
| 5510 | 5566 | if (type_has_bits(result_type)) { |
| 5511 | 5567 | LLVMValueRef awaiter_ret_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, frame_ret_start + 1, ""); |
| 5512 | 5568 | if (result_loc == nullptr) { |
| ... | ... | @@ -5554,28 +5610,8 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInst |
| 5554 | 5610 | // Early return: The async function has already completed. We must copy the result and |
| 5555 | 5611 | // the error return trace if applicable. |
| 5556 | 5612 | LLVMPositionBuilderAtEnd(g->builder, early_return_block); |
| 5557 | if (type_has_bits(result_type) && result_loc != nullptr) { | |
| 5558 | LLVMValueRef their_result_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, frame_ret_start, ""); | |
| 5559 | LLVMValueRef their_result_ptr = LLVMBuildLoad(g->builder, their_result_ptr_ptr, ""); | |
| 5560 | LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); | |
| 5561 | LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, result_loc, ptr_u8, ""); | |
| 5562 | LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, their_result_ptr, ptr_u8, ""); | |
| 5563 | bool is_volatile = false; | |
| 5564 | uint32_t abi_align = get_abi_alignment(g, result_type); | |
| 5565 | LLVMValueRef byte_count_val = LLVMConstInt(usize_type_ref, type_size(g, result_type), false); | |
| 5566 | ZigLLVMBuildMemCpy(g->builder, | |
| 5567 | dest_ptr_casted, abi_align, | |
| 5568 | src_ptr_casted, abi_align, byte_count_val, is_volatile); | |
| 5569 | } | |
| 5570 | if (codegen_fn_has_err_ret_tracing_arg(g, result_type)) { | |
| 5571 | LLVMValueRef their_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, | |
| 5572 | frame_index_trace_arg(g, result_type), ""); | |
| 5573 | LLVMValueRef src_trace_ptr = LLVMBuildLoad(g->builder, their_trace_ptr_ptr, ""); | |
| 5574 | LLVMValueRef dest_trace_ptr = get_cur_err_ret_trace_val(g, instruction->base.scope); | |
| 5575 | LLVMValueRef args[] = { dest_trace_ptr, src_trace_ptr }; | |
| 5576 | ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2, | |
| 5577 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); | |
| 5578 | } | |
| 5613 | gen_await_early_return(g, &instruction->base, target_frame_ptr, result_type, ptr_result_type, | |
| 5614 | result_loc, false); | |
| 5579 | 5615 | LLVMBuildBr(g->builder, end_bb); |
| 5580 | 5616 | |
| 5581 | 5617 | LLVMPositionBuilderAtEnd(g->builder, resume_bb); |
| ... | ... | @@ -6837,6 +6873,7 @@ static void set_global_tls(CodeGen *g, ZigVar *var, LLVMValueRef global_value) { |
| 6837 | 6873 | } |
| 6838 | 6874 | |
| 6839 | 6875 | static void do_code_gen(CodeGen *g) { |
| 6876 | Error err; | |
| 6840 | 6877 | assert(!g->errors.length); |
| 6841 | 6878 | |
| 6842 | 6879 | generate_error_name_table(g); |
| ... | ... | @@ -6850,6 +6887,8 @@ static void do_code_gen(CodeGen *g) { |
| 6850 | 6887 | // Generate debug info for it but that's it. |
| 6851 | 6888 | ConstExprValue *const_val = var->const_value; |
| 6852 | 6889 | assert(const_val->special != ConstValSpecialRuntime); |
| 6890 | if ((err = ir_resolve_lazy(g, var->decl_node, const_val))) | |
| 6891 | zig_unreachable(); | |
| 6853 | 6892 | if (const_val->type != var->var_type) { |
| 6854 | 6893 | zig_panic("TODO debug info for var with ptr casted value"); |
| 6855 | 6894 | } |
| ... | ... | @@ -6867,6 +6906,8 @@ static void do_code_gen(CodeGen *g) { |
| 6867 | 6906 | // Generate debug info for it but that's it. |
| 6868 | 6907 | ConstExprValue *const_val = var->const_value; |
| 6869 | 6908 | assert(const_val->special != ConstValSpecialRuntime); |
| 6909 | if ((err = ir_resolve_lazy(g, var->decl_node, const_val))) | |
| 6910 | zig_unreachable(); | |
| 6870 | 6911 | if (const_val->type != var->var_type) { |
| 6871 | 6912 | zig_panic("TODO debug info for var with ptr casted value"); |
| 6872 | 6913 | } |
| ... | ... | @@ -7200,6 +7241,12 @@ static void do_code_gen(CodeGen *g) { |
| 7200 | 7241 | LLVMSetModuleInlineAsm(g->module, buf_ptr(&g->global_asm)); |
| 7201 | 7242 | } |
| 7202 | 7243 | |
| 7244 | while (g->type_resolve_stack.length != 0) { | |
| 7245 | ZigType *ty = g->type_resolve_stack.last(); | |
| 7246 | if (type_resolve(g, ty, ResolveStatusLLVMFull)) | |
| 7247 | zig_unreachable(); | |
| 7248 | } | |
| 7249 | ||
| 7203 | 7250 | ZigLLVMDIBuilderFinalize(g->dbuilder); |
| 7204 | 7251 | |
| 7205 | 7252 | if (g->verbose_llvm_ir) { |
src/error.cpp+2| ... | ... | @@ -55,6 +55,8 @@ const char *err_str(Error err) { |
| 55 | 55 | case ErrorBrokenPipe: return "broken pipe"; |
| 56 | 56 | case ErrorNoSpaceLeft: return "no space left"; |
| 57 | 57 | case ErrorNoCCompilerInstalled: return "no C compiler installed"; |
| 58 | case ErrorNotLazy: return "not lazy"; | |
| 59 | case ErrorIsAsync: return "is async"; | |
| 58 | 60 | } |
| 59 | 61 | return "(invalid error)"; |
| 60 | 62 | } |
src/ir.cpp+247-86| ... | ... | @@ -3268,7 +3268,7 @@ static IrInstruction *ir_build_await_src(IrBuilder *irb, Scope *scope, AstNode * |
| 3268 | 3268 | return &instruction->base; |
| 3269 | 3269 | } |
| 3270 | 3270 | |
| 3271 | static IrInstruction *ir_build_await_gen(IrAnalyze *ira, IrInstruction *source_instruction, | |
| 3271 | static IrInstructionAwaitGen *ir_build_await_gen(IrAnalyze *ira, IrInstruction *source_instruction, | |
| 3272 | 3272 | IrInstruction *frame, ZigType *result_type, IrInstruction *result_loc) |
| 3273 | 3273 | { |
| 3274 | 3274 | IrInstructionAwaitGen *instruction = ir_build_instruction<IrInstructionAwaitGen>(&ira->new_irb, |
| ... | ... | @@ -3280,7 +3280,7 @@ static IrInstruction *ir_build_await_gen(IrAnalyze *ira, IrInstruction *source_i |
| 3280 | 3280 | ir_ref_instruction(frame, ira->new_irb.current_basic_block); |
| 3281 | 3281 | if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); |
| 3282 | 3282 | |
| 3283 | return &instruction->base; | |
| 3283 | return instruction; | |
| 3284 | 3284 | } |
| 3285 | 3285 | |
| 3286 | 3286 | static IrInstruction *ir_build_resume(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *frame) { |
| ... | ... | @@ -10640,7 +10640,9 @@ static void ir_finish_bb(IrAnalyze *ira) { |
| 10640 | 10640 | |
| 10641 | 10641 | static IrInstruction *ir_unreach_error(IrAnalyze *ira) { |
| 10642 | 10642 | ira->old_bb_index = SIZE_MAX; |
| 10643 | assert(ira->new_irb.exec->first_err_trace_msg != nullptr); | |
| 10643 | if (ira->new_irb.exec->first_err_trace_msg == nullptr) { | |
| 10644 | ira->new_irb.exec->first_err_trace_msg = ira->codegen->trace_err; | |
| 10645 | } | |
| 10644 | 10646 | return ira->codegen->unreach_instruction; |
| 10645 | 10647 | } |
| 10646 | 10648 | |
| ... | ... | @@ -12932,7 +12934,52 @@ static bool optional_value_is_null(ConstExprValue *val) { |
| 12932 | 12934 | } |
| 12933 | 12935 | } |
| 12934 | 12936 | |
| 12937 | // Returns ErrorNotLazy when the value cannot be determined | |
| 12938 | static Error lazy_cmp_zero(AstNode *source_node, ConstExprValue *val, Cmp *result) { | |
| 12939 | Error err; | |
| 12940 | ||
| 12941 | switch (val->special) { | |
| 12942 | case ConstValSpecialRuntime: | |
| 12943 | case ConstValSpecialUndef: | |
| 12944 | return ErrorNotLazy; | |
| 12945 | case ConstValSpecialStatic: | |
| 12946 | switch (val->type->id) { | |
| 12947 | case ZigTypeIdComptimeInt: | |
| 12948 | case ZigTypeIdInt: | |
| 12949 | *result = bigint_cmp_zero(&val->data.x_bigint); | |
| 12950 | return ErrorNone; | |
| 12951 | default: | |
| 12952 | return ErrorNotLazy; | |
| 12953 | } | |
| 12954 | case ConstValSpecialLazy: | |
| 12955 | switch (val->data.x_lazy->id) { | |
| 12956 | case LazyValueIdInvalid: | |
| 12957 | zig_unreachable(); | |
| 12958 | case LazyValueIdAlignOf: | |
| 12959 | *result = CmpGT; | |
| 12960 | return ErrorNone; | |
| 12961 | case LazyValueIdSizeOf: { | |
| 12962 | LazyValueSizeOf *lazy_size_of = reinterpret_cast<LazyValueSizeOf *>(val->data.x_lazy); | |
| 12963 | IrAnalyze *ira = lazy_size_of->ira; | |
| 12964 | bool is_zero_bits; | |
| 12965 | if ((err = type_val_resolve_zero_bits(ira->codegen, &lazy_size_of->target_type->value, | |
| 12966 | nullptr, nullptr, &is_zero_bits))) | |
| 12967 | { | |
| 12968 | return err; | |
| 12969 | } | |
| 12970 | *result = is_zero_bits ? CmpEQ : CmpGT; | |
| 12971 | return ErrorNone; | |
| 12972 | } | |
| 12973 | default: | |
| 12974 | return ErrorNotLazy; | |
| 12975 | } | |
| 12976 | } | |
| 12977 | zig_unreachable(); | |
| 12978 | } | |
| 12979 | ||
| 12935 | 12980 | static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { |
| 12981 | Error err; | |
| 12982 | ||
| 12936 | 12983 | IrInstruction *op1 = bin_op_instruction->op1->child; |
| 12937 | 12984 | if (type_is_invalid(op1->value.type)) |
| 12938 | 12985 | return ira->codegen->invalid_instruction; |
| ... | ... | @@ -13182,6 +13229,50 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * |
| 13182 | 13229 | } |
| 13183 | 13230 | |
| 13184 | 13231 | if (one_possible_value || (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2))) { |
| 13232 | { | |
| 13233 | // Before resolving the values, we special case comparisons against zero. These can often be done | |
| 13234 | // without resolving lazy values, preventing potential dependency loops. | |
| 13235 | Cmp op1_cmp_zero; | |
| 13236 | if ((err = lazy_cmp_zero(bin_op_instruction->base.source_node, &casted_op1->value, &op1_cmp_zero))) { | |
| 13237 | if (err == ErrorNotLazy) goto never_mind_just_calculate_it_normally; | |
| 13238 | return ira->codegen->invalid_instruction; | |
| 13239 | } | |
| 13240 | Cmp op2_cmp_zero; | |
| 13241 | if ((err = lazy_cmp_zero(bin_op_instruction->base.source_node, &casted_op2->value, &op2_cmp_zero))) { | |
| 13242 | if (err == ErrorNotLazy) goto never_mind_just_calculate_it_normally; | |
| 13243 | return ira->codegen->invalid_instruction; | |
| 13244 | } | |
| 13245 | bool can_cmp_zero = false; | |
| 13246 | Cmp cmp_result; | |
| 13247 | if (op1_cmp_zero == CmpEQ && op2_cmp_zero == CmpEQ) { | |
| 13248 | can_cmp_zero = true; | |
| 13249 | cmp_result = CmpEQ; | |
| 13250 | } else if (op1_cmp_zero == CmpGT && op2_cmp_zero == CmpEQ) { | |
| 13251 | can_cmp_zero = true; | |
| 13252 | cmp_result = CmpGT; | |
| 13253 | } else if (op1_cmp_zero == CmpEQ && op2_cmp_zero == CmpGT) { | |
| 13254 | can_cmp_zero = true; | |
| 13255 | cmp_result = CmpLT; | |
| 13256 | } else if (op1_cmp_zero == CmpLT && op2_cmp_zero == CmpEQ) { | |
| 13257 | can_cmp_zero = true; | |
| 13258 | cmp_result = CmpLT; | |
| 13259 | } else if (op1_cmp_zero == CmpEQ && op2_cmp_zero == CmpLT) { | |
| 13260 | can_cmp_zero = true; | |
| 13261 | cmp_result = CmpGT; | |
| 13262 | } else if (op1_cmp_zero == CmpLT && op2_cmp_zero == CmpGT) { | |
| 13263 | can_cmp_zero = true; | |
| 13264 | cmp_result = CmpLT; | |
| 13265 | } else if (op1_cmp_zero == CmpGT && op2_cmp_zero == CmpLT) { | |
| 13266 | can_cmp_zero = true; | |
| 13267 | cmp_result = CmpGT; | |
| 13268 | } | |
| 13269 | if (can_cmp_zero) { | |
| 13270 | bool answer = resolve_cmp_op_id(op_id, cmp_result); | |
| 13271 | return ir_const_bool(ira, &bin_op_instruction->base, answer); | |
| 13272 | } | |
| 13273 | } | |
| 13274 | never_mind_just_calculate_it_normally: | |
| 13275 | ||
| 13185 | 13276 | ConstExprValue *op1_val = one_possible_value ? &casted_op1->value : ir_resolve_const(ira, casted_op1, UndefBad); |
| 13186 | 13277 | if (op1_val == nullptr) |
| 13187 | 13278 | return ira->codegen->invalid_instruction; |
| ... | ... | @@ -14626,28 +14717,23 @@ static IrInstruction *ir_analyze_instruction_error_return_trace(IrAnalyze *ira, |
| 14626 | 14717 | static IrInstruction *ir_analyze_instruction_error_union(IrAnalyze *ira, |
| 14627 | 14718 | IrInstructionErrorUnion *instruction) |
| 14628 | 14719 | { |
| 14629 | Error err; | |
| 14630 | ||
| 14631 | ZigType *err_set_type = ir_resolve_type(ira, instruction->err_set->child); | |
| 14632 | if (type_is_invalid(err_set_type)) | |
| 14633 | return ira->codegen->invalid_instruction; | |
| 14720 | IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type); | |
| 14721 | result->value.special = ConstValSpecialLazy; | |
| 14634 | 14722 | |
| 14635 | ZigType *payload_type = ir_resolve_type(ira, instruction->payload->child); | |
| 14636 | if (type_is_invalid(payload_type)) | |
| 14637 | return ira->codegen->invalid_instruction; | |
| 14723 | LazyValueErrUnionType *lazy_err_union_type = allocate<LazyValueErrUnionType>(1); | |
| 14724 | lazy_err_union_type->ira = ira; | |
| 14725 | result->value.data.x_lazy = &lazy_err_union_type->base; | |
| 14726 | lazy_err_union_type->base.id = LazyValueIdErrUnionType; | |
| 14638 | 14727 | |
| 14639 | if (err_set_type->id != ZigTypeIdErrorSet) { | |
| 14640 | ir_add_error(ira, instruction->err_set->child, | |
| 14641 | buf_sprintf("expected error set type, found type '%s'", | |
| 14642 | buf_ptr(&err_set_type->name))); | |
| 14728 | lazy_err_union_type->err_set_type = instruction->err_set->child; | |
| 14729 | if (ir_resolve_type_lazy(ira, lazy_err_union_type->err_set_type) == nullptr) | |
| 14643 | 14730 | return ira->codegen->invalid_instruction; |
| 14644 | } | |
| 14645 | 14731 | |
| 14646 | if ((err = type_resolve(ira->codegen, payload_type, ResolveStatusSizeKnown))) | |
| 14732 | lazy_err_union_type->payload_type = instruction->payload->child; | |
| 14733 | if (ir_resolve_type_lazy(ira, lazy_err_union_type->payload_type) == nullptr) | |
| 14647 | 14734 | return ira->codegen->invalid_instruction; |
| 14648 | ZigType *result_type = get_error_union_type(ira->codegen, err_set_type, payload_type); | |
| 14649 | 14735 | |
| 14650 | return ir_const_type(ira, &instruction->base, result_type); | |
| 14736 | return result; | |
| 14651 | 14737 | } |
| 14652 | 14738 | |
| 14653 | 14739 | static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_inst, ZigType *var_type, |
| ... | ... | @@ -16815,12 +16901,6 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 16815 | 16901 | return ira->codegen->invalid_instruction; |
| 16816 | 16902 | |
| 16817 | 16903 | bool safety_check_on = elem_ptr_instruction->safety_check_on; |
| 16818 | if ((err = type_resolve(ira->codegen, return_type->data.pointer.child_type, ResolveStatusSizeKnown))) | |
| 16819 | return ira->codegen->invalid_instruction; | |
| 16820 | ||
| 16821 | uint64_t elem_size = type_size(ira->codegen, return_type->data.pointer.child_type); | |
| 16822 | uint64_t abi_align = get_abi_alignment(ira->codegen, return_type->data.pointer.child_type); | |
| 16823 | uint64_t ptr_align = get_ptr_align(ira->codegen, return_type); | |
| 16824 | 16904 | if (instr_is_comptime(casted_elem_index)) { |
| 16825 | 16905 | uint64_t index = bigint_as_u64(&casted_elem_index->value.data.x_bigint); |
| 16826 | 16906 | if (array_type->id == ZigTypeIdArray) { |
| ... | ... | @@ -16834,8 +16914,16 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 16834 | 16914 | safety_check_on = false; |
| 16835 | 16915 | } |
| 16836 | 16916 | |
| 16837 | { | |
| 16917 | if (return_type->data.pointer.explicit_alignment != 0) { | |
| 16838 | 16918 | // figure out the largest alignment possible |
| 16919 | ||
| 16920 | if ((err = type_resolve(ira->codegen, return_type->data.pointer.child_type, ResolveStatusSizeKnown))) | |
| 16921 | return ira->codegen->invalid_instruction; | |
| 16922 | ||
| 16923 | uint64_t elem_size = type_size(ira->codegen, return_type->data.pointer.child_type); | |
| 16924 | uint64_t abi_align = get_abi_alignment(ira->codegen, return_type->data.pointer.child_type); | |
| 16925 | uint64_t ptr_align = get_ptr_align(ira->codegen, return_type); | |
| 16926 | ||
| 16839 | 16927 | uint64_t chosen_align = abi_align; |
| 16840 | 16928 | if (ptr_align >= abi_align) { |
| 16841 | 16929 | while (ptr_align > abi_align) { |
| ... | ... | @@ -17064,15 +17152,24 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 17064 | 17152 | case ReqCompTimeNo: |
| 17065 | 17153 | break; |
| 17066 | 17154 | } |
| 17067 | if (ptr_align < abi_align) { | |
| 17068 | if (elem_size >= ptr_align && elem_size % ptr_align == 0) { | |
| 17069 | return_type = adjust_ptr_align(ira->codegen, return_type, ptr_align); | |
| 17155 | ||
| 17156 | if (return_type->data.pointer.explicit_alignment != 0) { | |
| 17157 | if ((err = type_resolve(ira->codegen, return_type->data.pointer.child_type, ResolveStatusSizeKnown))) | |
| 17158 | return ira->codegen->invalid_instruction; | |
| 17159 | ||
| 17160 | uint64_t elem_size = type_size(ira->codegen, return_type->data.pointer.child_type); | |
| 17161 | uint64_t abi_align = get_abi_alignment(ira->codegen, return_type->data.pointer.child_type); | |
| 17162 | uint64_t ptr_align = get_ptr_align(ira->codegen, return_type); | |
| 17163 | if (ptr_align < abi_align) { | |
| 17164 | if (elem_size >= ptr_align && elem_size % ptr_align == 0) { | |
| 17165 | return_type = adjust_ptr_align(ira->codegen, return_type, ptr_align); | |
| 17166 | } else { | |
| 17167 | // can't get here because guaranteed elem_size >= abi_align | |
| 17168 | zig_unreachable(); | |
| 17169 | } | |
| 17070 | 17170 | } else { |
| 17071 | // can't get here because guaranteed elem_size >= abi_align | |
| 17072 | zig_unreachable(); | |
| 17171 | return_type = adjust_ptr_align(ira->codegen, return_type, abi_align); | |
| 17073 | 17172 | } |
| 17074 | } else { | |
| 17075 | return_type = adjust_ptr_align(ira->codegen, return_type, abi_align); | |
| 17076 | 17173 | } |
| 17077 | 17174 | } |
| 17078 | 17175 | |
| ... | ... | @@ -18071,54 +18168,20 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira, |
| 18071 | 18168 | zig_unreachable(); |
| 18072 | 18169 | } |
| 18073 | 18170 | |
| 18074 | static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, | |
| 18075 | IrInstructionSizeOf *size_of_instruction) | |
| 18076 | { | |
| 18077 | Error err; | |
| 18078 | IrInstruction *type_value = size_of_instruction->type_value->child; | |
| 18079 | ZigType *type_entry = ir_resolve_type(ira, type_value); | |
| 18171 | static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, IrInstructionSizeOf *instruction) { | |
| 18172 | IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_num_lit_int); | |
| 18173 | result->value.special = ConstValSpecialLazy; | |
| 18080 | 18174 | |
| 18081 | if ((err = type_resolve(ira->codegen, type_entry, ResolveStatusSizeKnown))) | |
| 18175 | LazyValueSizeOf *lazy_size_of = allocate<LazyValueSizeOf>(1); | |
| 18176 | lazy_size_of->ira = ira; | |
| 18177 | result->value.data.x_lazy = &lazy_size_of->base; | |
| 18178 | lazy_size_of->base.id = LazyValueIdSizeOf; | |
| 18179 | ||
| 18180 | lazy_size_of->target_type = instruction->type_value->child; | |
| 18181 | if (ir_resolve_type_lazy(ira, lazy_size_of->target_type) == nullptr) | |
| 18082 | 18182 | return ira->codegen->invalid_instruction; |
| 18083 | 18183 | |
| 18084 | switch (type_entry->id) { | |
| 18085 | case ZigTypeIdInvalid: // handled above | |
| 18086 | zig_unreachable(); | |
| 18087 | case ZigTypeIdUnreachable: | |
| 18088 | case ZigTypeIdUndefined: | |
| 18089 | case ZigTypeIdNull: | |
| 18090 | case ZigTypeIdBoundFn: | |
| 18091 | case ZigTypeIdArgTuple: | |
| 18092 | case ZigTypeIdOpaque: | |
| 18093 | ir_add_error_node(ira, type_value->source_node, | |
| 18094 | buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name))); | |
| 18095 | return ira->codegen->invalid_instruction; | |
| 18096 | case ZigTypeIdMetaType: | |
| 18097 | case ZigTypeIdEnumLiteral: | |
| 18098 | case ZigTypeIdComptimeFloat: | |
| 18099 | case ZigTypeIdComptimeInt: | |
| 18100 | case ZigTypeIdVoid: | |
| 18101 | case ZigTypeIdBool: | |
| 18102 | case ZigTypeIdInt: | |
| 18103 | case ZigTypeIdFloat: | |
| 18104 | case ZigTypeIdPointer: | |
| 18105 | case ZigTypeIdArray: | |
| 18106 | case ZigTypeIdStruct: | |
| 18107 | case ZigTypeIdOptional: | |
| 18108 | case ZigTypeIdErrorUnion: | |
| 18109 | case ZigTypeIdErrorSet: | |
| 18110 | case ZigTypeIdEnum: | |
| 18111 | case ZigTypeIdUnion: | |
| 18112 | case ZigTypeIdFn: | |
| 18113 | case ZigTypeIdVector: | |
| 18114 | case ZigTypeIdFnFrame: | |
| 18115 | case ZigTypeIdAnyFrame: | |
| 18116 | { | |
| 18117 | uint64_t size_in_bytes = type_size(ira->codegen, type_entry); | |
| 18118 | return ir_const_unsigned(ira, &size_of_instruction->base, size_in_bytes); | |
| 18119 | } | |
| 18120 | } | |
| 18121 | zig_unreachable(); | |
| 18184 | return result; | |
| 18122 | 18185 | } |
| 18123 | 18186 | |
| 18124 | 18187 | static IrInstruction *ir_analyze_test_non_null(IrAnalyze *ira, IrInstruction *source_inst, IrInstruction *value) { |
| ... | ... | @@ -24702,18 +24765,22 @@ static IrInstruction *ir_analyze_instruction_suspend_finish(IrAnalyze *ira, |
| 24702 | 24765 | } |
| 24703 | 24766 | |
| 24704 | 24767 | static IrInstruction *analyze_frame_ptr_to_anyframe_T(IrAnalyze *ira, IrInstruction *source_instr, |
| 24705 | IrInstruction *frame_ptr) | |
| 24768 | IrInstruction *frame_ptr, ZigFn **target_fn) | |
| 24706 | 24769 | { |
| 24707 | 24770 | if (type_is_invalid(frame_ptr->value.type)) |
| 24708 | 24771 | return ira->codegen->invalid_instruction; |
| 24709 | 24772 | |
| 24773 | *target_fn = nullptr; | |
| 24774 | ||
| 24710 | 24775 | ZigType *result_type; |
| 24711 | 24776 | IrInstruction *frame; |
| 24712 | 24777 | if (frame_ptr->value.type->id == ZigTypeIdPointer && |
| 24713 | 24778 | frame_ptr->value.type->data.pointer.ptr_len == PtrLenSingle && |
| 24714 | 24779 | frame_ptr->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame) |
| 24715 | 24780 | { |
| 24716 | result_type = frame_ptr->value.type->data.pointer.child_type->data.frame.fn->type_entry->data.fn.fn_type_id.return_type; | |
| 24781 | ZigFn *func = frame_ptr->value.type->data.pointer.child_type->data.frame.fn; | |
| 24782 | result_type = func->type_entry->data.fn.fn_type_id.return_type; | |
| 24783 | *target_fn = func; | |
| 24717 | 24784 | frame = frame_ptr; |
| 24718 | 24785 | } else { |
| 24719 | 24786 | frame = ir_get_deref(ira, source_instr, frame_ptr, nullptr); |
| ... | ... | @@ -24721,7 +24788,9 @@ static IrInstruction *analyze_frame_ptr_to_anyframe_T(IrAnalyze *ira, IrInstruct |
| 24721 | 24788 | frame->value.type->data.pointer.ptr_len == PtrLenSingle && |
| 24722 | 24789 | frame->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame) |
| 24723 | 24790 | { |
| 24724 | result_type = frame->value.type->data.pointer.child_type->data.frame.fn->type_entry->data.fn.fn_type_id.return_type; | |
| 24791 | ZigFn *func = frame->value.type->data.pointer.child_type->data.frame.fn; | |
| 24792 | result_type = func->type_entry->data.fn.fn_type_id.return_type; | |
| 24793 | *target_fn = func; | |
| 24725 | 24794 | } else if (frame->value.type->id != ZigTypeIdAnyFrame || |
| 24726 | 24795 | frame->value.type->data.any_frame.result_type == nullptr) |
| 24727 | 24796 | { |
| ... | ... | @@ -24742,7 +24811,11 @@ static IrInstruction *analyze_frame_ptr_to_anyframe_T(IrAnalyze *ira, IrInstruct |
| 24742 | 24811 | } |
| 24743 | 24812 | |
| 24744 | 24813 | static IrInstruction *ir_analyze_instruction_await(IrAnalyze *ira, IrInstructionAwaitSrc *instruction) { |
| 24745 | IrInstruction *frame = analyze_frame_ptr_to_anyframe_T(ira, &instruction->base, instruction->frame->child); | |
| 24814 | IrInstruction *operand = instruction->frame->child; | |
| 24815 | if (type_is_invalid(operand->value.type)) | |
| 24816 | return ira->codegen->invalid_instruction; | |
| 24817 | ZigFn *target_fn; | |
| 24818 | IrInstruction *frame = analyze_frame_ptr_to_anyframe_T(ira, &instruction->base, operand, &target_fn); | |
| 24746 | 24819 | if (type_is_invalid(frame->value.type)) |
| 24747 | 24820 | return ira->codegen->invalid_instruction; |
| 24748 | 24821 | |
| ... | ... | @@ -24751,8 +24824,11 @@ static IrInstruction *ir_analyze_instruction_await(IrAnalyze *ira, IrInstruction |
| 24751 | 24824 | ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec); |
| 24752 | 24825 | ir_assert(fn_entry != nullptr, &instruction->base); |
| 24753 | 24826 | |
| 24754 | if (fn_entry->inferred_async_node == nullptr) { | |
| 24755 | fn_entry->inferred_async_node = instruction->base.source_node; | |
| 24827 | // If it's not @Frame(func) then it's definitely a suspend point | |
| 24828 | if (target_fn == nullptr) { | |
| 24829 | if (fn_entry->inferred_async_node == nullptr) { | |
| 24830 | fn_entry->inferred_async_node = instruction->base.source_node; | |
| 24831 | } | |
| 24756 | 24832 | } |
| 24757 | 24833 | |
| 24758 | 24834 | if (type_can_fail(result_type)) { |
| ... | ... | @@ -24769,8 +24845,10 @@ static IrInstruction *ir_analyze_instruction_await(IrAnalyze *ira, IrInstruction |
| 24769 | 24845 | result_loc = nullptr; |
| 24770 | 24846 | } |
| 24771 | 24847 | |
| 24772 | IrInstruction *result = ir_build_await_gen(ira, &instruction->base, frame, result_type, result_loc); | |
| 24773 | return ir_finish_anal(ira, result); | |
| 24848 | IrInstructionAwaitGen *result = ir_build_await_gen(ira, &instruction->base, frame, result_type, result_loc); | |
| 24849 | result->target_fn = target_fn; | |
| 24850 | fn_entry->await_list.append(result); | |
| 24851 | return ir_finish_anal(ira, &result->base); | |
| 24774 | 24852 | } |
| 24775 | 24853 | |
| 24776 | 24854 | static IrInstruction *ir_analyze_instruction_resume(IrAnalyze *ira, IrInstructionResume *instruction) { |
| ... | ... | @@ -25553,6 +25631,61 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) { |
| 25553 | 25631 | bigint_init_unsigned(&val->data.x_bigint, align_in_bytes); |
| 25554 | 25632 | return ErrorNone; |
| 25555 | 25633 | } |
| 25634 | case LazyValueIdSizeOf: { | |
| 25635 | LazyValueSizeOf *lazy_size_of = reinterpret_cast<LazyValueSizeOf *>(val->data.x_lazy); | |
| 25636 | IrAnalyze *ira = lazy_size_of->ira; | |
| 25637 | ||
| 25638 | if (lazy_size_of->target_type->value.special == ConstValSpecialStatic) { | |
| 25639 | switch (lazy_size_of->target_type->value.data.x_type->id) { | |
| 25640 | case ZigTypeIdInvalid: // handled above | |
| 25641 | zig_unreachable(); | |
| 25642 | case ZigTypeIdUnreachable: | |
| 25643 | case ZigTypeIdUndefined: | |
| 25644 | case ZigTypeIdNull: | |
| 25645 | case ZigTypeIdBoundFn: | |
| 25646 | case ZigTypeIdArgTuple: | |
| 25647 | case ZigTypeIdOpaque: | |
| 25648 | ir_add_error(ira, lazy_size_of->target_type, | |
| 25649 | buf_sprintf("no size available for type '%s'", | |
| 25650 | buf_ptr(&lazy_size_of->target_type->value.data.x_type->name))); | |
| 25651 | return ErrorSemanticAnalyzeFail; | |
| 25652 | case ZigTypeIdMetaType: | |
| 25653 | case ZigTypeIdEnumLiteral: | |
| 25654 | case ZigTypeIdComptimeFloat: | |
| 25655 | case ZigTypeIdComptimeInt: | |
| 25656 | case ZigTypeIdVoid: | |
| 25657 | case ZigTypeIdBool: | |
| 25658 | case ZigTypeIdInt: | |
| 25659 | case ZigTypeIdFloat: | |
| 25660 | case ZigTypeIdPointer: | |
| 25661 | case ZigTypeIdArray: | |
| 25662 | case ZigTypeIdStruct: | |
| 25663 | case ZigTypeIdOptional: | |
| 25664 | case ZigTypeIdErrorUnion: | |
| 25665 | case ZigTypeIdErrorSet: | |
| 25666 | case ZigTypeIdEnum: | |
| 25667 | case ZigTypeIdUnion: | |
| 25668 | case ZigTypeIdFn: | |
| 25669 | case ZigTypeIdVector: | |
| 25670 | case ZigTypeIdFnFrame: | |
| 25671 | case ZigTypeIdAnyFrame: | |
| 25672 | break; | |
| 25673 | } | |
| 25674 | } | |
| 25675 | ||
| 25676 | uint64_t abi_size; | |
| 25677 | uint64_t size_in_bits; | |
| 25678 | if ((err = type_val_resolve_abi_size(ira->codegen, source_node, &lazy_size_of->target_type->value, | |
| 25679 | &abi_size, &size_in_bits))) | |
| 25680 | { | |
| 25681 | return err; | |
| 25682 | } | |
| 25683 | ||
| 25684 | val->special = ConstValSpecialStatic; | |
| 25685 | assert(val->type->id == ZigTypeIdComptimeInt); | |
| 25686 | bigint_init_unsigned(&val->data.x_bigint, abi_size); | |
| 25687 | return ErrorNone; | |
| 25688 | } | |
| 25556 | 25689 | case LazyValueIdSliceType: { |
| 25557 | 25690 | LazyValueSliceType *lazy_slice_type = reinterpret_cast<LazyValueSliceType *>(val->data.x_lazy); |
| 25558 | 25691 | IrAnalyze *ira = lazy_slice_type->ira; |
| ... | ... | @@ -25698,6 +25831,34 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) { |
| 25698 | 25831 | val->data.x_type = fn_type; |
| 25699 | 25832 | return ErrorNone; |
| 25700 | 25833 | } |
| 25834 | case LazyValueIdErrUnionType: { | |
| 25835 | LazyValueErrUnionType *lazy_err_union_type = | |
| 25836 | reinterpret_cast<LazyValueErrUnionType *>(val->data.x_lazy); | |
| 25837 | IrAnalyze *ira = lazy_err_union_type->ira; | |
| 25838 | ||
| 25839 | ZigType *err_set_type = ir_resolve_type(ira, lazy_err_union_type->err_set_type); | |
| 25840 | if (type_is_invalid(err_set_type)) | |
| 25841 | return ErrorSemanticAnalyzeFail; | |
| 25842 | ||
| 25843 | ZigType *payload_type = ir_resolve_type(ira, lazy_err_union_type->payload_type); | |
| 25844 | if (type_is_invalid(payload_type)) | |
| 25845 | return ErrorSemanticAnalyzeFail; | |
| 25846 | ||
| 25847 | if (err_set_type->id != ZigTypeIdErrorSet) { | |
| 25848 | ir_add_error(ira, lazy_err_union_type->err_set_type, | |
| 25849 | buf_sprintf("expected error set type, found type '%s'", | |
| 25850 | buf_ptr(&err_set_type->name))); | |
| 25851 | return ErrorSemanticAnalyzeFail; | |
| 25852 | } | |
| 25853 | ||
| 25854 | if ((err = type_resolve(ira->codegen, payload_type, ResolveStatusSizeKnown))) | |
| 25855 | return ErrorSemanticAnalyzeFail; | |
| 25856 | ||
| 25857 | assert(val->type->id == ZigTypeIdMetaType); | |
| 25858 | val->data.x_type = get_error_union_type(ira->codegen, err_set_type, payload_type); | |
| 25859 | val->special = ConstValSpecialStatic; | |
| 25860 | return ErrorNone; | |
| 25861 | } | |
| 25701 | 25862 | } |
| 25702 | 25863 | zig_unreachable(); |
| 25703 | 25864 | } |
src/list.hpp+11| ... | ... | @@ -74,6 +74,17 @@ struct ZigList { |
| 74 | 74 | capacity = better_capacity; |
| 75 | 75 | } |
| 76 | 76 | |
| 77 | T swap_remove(size_t index) { | |
| 78 | if (length - 1 == index) return pop(); | |
| 79 | ||
| 80 | assert(index != SIZE_MAX); | |
| 81 | assert(index < length); | |
| 82 | ||
| 83 | T old_item = items[index]; | |
| 84 | items[index] = pop(); | |
| 85 | return old_item; | |
| 86 | } | |
| 87 | ||
| 77 | 88 | T *items; |
| 78 | 89 | size_t length; |
| 79 | 90 | size_t capacity; |
src/userland.h+2| ... | ... | @@ -75,6 +75,8 @@ enum Error { |
| 75 | 75 | ErrorOperationAborted, |
| 76 | 76 | ErrorBrokenPipe, |
| 77 | 77 | ErrorNoSpaceLeft, |
| 78 | ErrorNotLazy, | |
| 79 | ErrorIsAsync, | |
| 78 | 80 | }; |
| 79 | 81 | |
| 80 | 82 | // ABI warning |
std/hash/auto_hash.zig+12-2| ... | ... | @@ -1,5 +1,6 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | const assert = std.debug.assert; | |
| 3 | 4 | const mem = std.mem; |
| 4 | 5 | const meta = std.meta; |
| 5 | 6 | |
| ... | ... | @@ -165,8 +166,17 @@ pub fn hash(hasher: var, key: var, comptime strat: HashStrategy) void { |
| 165 | 166 | /// Slices are rejected to avoid ambiguity on the user's intention. |
| 166 | 167 | pub fn autoHash(hasher: var, key: var) void { |
| 167 | 168 | const Key = @typeOf(key); |
| 168 | if (comptime meta.trait.isSlice(Key)) | |
| 169 | @compileError("std.auto_hash.autoHash does not allow slices (here " ++ @typeName(Key) ++ " because the intent is unclear. Consider using std.auto_hash.hash or providing your own hash function instead."); | |
| 169 | if (comptime meta.trait.isSlice(Key)) { | |
| 170 | comptime assert(@hasDecl(std, "StringHashMap")); // detect when the following message needs updated | |
| 171 | const extra_help = if (Key == []const u8) | |
| 172 | " Consider std.StringHashMap for hashing the contents of []const u8." | |
| 173 | else | |
| 174 | ""; | |
| 175 | ||
| 176 | @compileError("std.auto_hash.autoHash does not allow slices (here " ++ @typeName(Key) ++ | |
| 177 | ") because the intent is unclear. Consider using std.auto_hash.hash or providing your own hash function instead." ++ | |
| 178 | extra_help); | |
| 179 | } | |
| 170 | 180 | |
| 171 | 181 | hash(hasher, key, .Shallow); |
| 172 | 182 | } |
std/mem.zig+6-5| ... | ... | @@ -75,15 +75,16 @@ pub const Allocator = struct { |
| 75 | 75 | new_alignment: u29, |
| 76 | 76 | ) []u8, |
| 77 | 77 | |
| 78 | /// Call `destroy` with the result. | |
| 79 | /// Returns undefined memory. | |
| 78 | /// Returns a pointer to undefined memory. | |
| 79 | /// Call `destroy` with the result to free the memory. | |
| 80 | 80 | pub fn create(self: *Allocator, comptime T: type) Error!*T { |
| 81 | 81 | if (@sizeOf(T) == 0) return &(T{}); |
| 82 | 82 | const slice = try self.alloc(T, 1); |
| 83 | 83 | return &slice[0]; |
| 84 | 84 | } |
| 85 | 85 | |
| 86 | /// `ptr` should be the return value of `create` | |
| 86 | /// `ptr` should be the return value of `create`, or otherwise | |
| 87 | /// have the same address and alignment property. | |
| 87 | 88 | pub fn destroy(self: *Allocator, ptr: var) void { |
| 88 | 89 | const T = @typeOf(ptr).Child; |
| 89 | 90 | if (@sizeOf(T) == 0) return; |
| ... | ... | @@ -92,7 +93,7 @@ pub const Allocator = struct { |
| 92 | 93 | assert(shrink_result.len == 0); |
| 93 | 94 | } |
| 94 | 95 | |
| 95 | pub fn alloc(self: *Allocator, comptime T: type, n: usize) ![]T { | |
| 96 | pub fn alloc(self: *Allocator, comptime T: type, n: usize) Error![]T { | |
| 96 | 97 | return self.alignedAlloc(T, @alignOf(T), n); |
| 97 | 98 | } |
| 98 | 99 | |
| ... | ... | @@ -101,7 +102,7 @@ pub const Allocator = struct { |
| 101 | 102 | comptime T: type, |
| 102 | 103 | comptime alignment: u29, |
| 103 | 104 | n: usize, |
| 104 | ) ![]align(alignment) T { | |
| 105 | ) Error![]align(alignment) T { | |
| 105 | 106 | if (n == 0) { |
| 106 | 107 | return ([*]align(alignment) T)(undefined)[0..0]; |
| 107 | 108 | } |
std/zig/parser_test.zig+111-1| ... | ... | @@ -210,6 +210,103 @@ test "zig fmt: comment to disable/enable zig fmt" { |
| 210 | 210 | ); |
| 211 | 211 | } |
| 212 | 212 | |
| 213 | test "zig fmt: line comment following 'zig fmt: off'" { | |
| 214 | try testCanonical( | |
| 215 | \\// zig fmt: off | |
| 216 | \\// Test | |
| 217 | \\const e = f; | |
| 218 | ); | |
| 219 | } | |
| 220 | ||
| 221 | test "zig fmt: doc comment following 'zig fmt: off'" { | |
| 222 | try testCanonical( | |
| 223 | \\// zig fmt: off | |
| 224 | \\/// test | |
| 225 | \\const e = f; | |
| 226 | ); | |
| 227 | } | |
| 228 | ||
| 229 | test "zig fmt: line and doc comment following 'zig fmt: off'" { | |
| 230 | try testCanonical( | |
| 231 | \\// zig fmt: off | |
| 232 | \\// test 1 | |
| 233 | \\/// test 2 | |
| 234 | \\const e = f; | |
| 235 | ); | |
| 236 | } | |
| 237 | ||
| 238 | test "zig fmt: doc and line comment following 'zig fmt: off'" { | |
| 239 | try testCanonical( | |
| 240 | \\// zig fmt: off | |
| 241 | \\/// test 1 | |
| 242 | \\// test 2 | |
| 243 | \\const e = f; | |
| 244 | ); | |
| 245 | } | |
| 246 | ||
| 247 | test "zig fmt: alternating 'zig fmt: off' and 'zig fmt: on'" { | |
| 248 | try testCanonical( | |
| 249 | \\// zig fmt: off | |
| 250 | \\// zig fmt: on | |
| 251 | \\// zig fmt: off | |
| 252 | \\const e = f; | |
| 253 | \\// zig fmt: off | |
| 254 | \\// zig fmt: on | |
| 255 | \\// zig fmt: off | |
| 256 | \\const a = b; | |
| 257 | \\// zig fmt: on | |
| 258 | \\const c = d; | |
| 259 | \\// zig fmt: on | |
| 260 | \\ | |
| 261 | ); | |
| 262 | } | |
| 263 | ||
| 264 | test "zig fmt: line comment following 'zig fmt: on'" { | |
| 265 | try testCanonical( | |
| 266 | \\// zig fmt: off | |
| 267 | \\const e = f; | |
| 268 | \\// zig fmt: on | |
| 269 | \\// test | |
| 270 | \\const e = f; | |
| 271 | \\ | |
| 272 | ); | |
| 273 | } | |
| 274 | ||
| 275 | test "zig fmt: doc comment following 'zig fmt: on'" { | |
| 276 | try testCanonical( | |
| 277 | \\// zig fmt: off | |
| 278 | \\const e = f; | |
| 279 | \\// zig fmt: on | |
| 280 | \\/// test | |
| 281 | \\const e = f; | |
| 282 | \\ | |
| 283 | ); | |
| 284 | } | |
| 285 | ||
| 286 | test "zig fmt: line and doc comment following 'zig fmt: on'" { | |
| 287 | try testCanonical( | |
| 288 | \\// zig fmt: off | |
| 289 | \\const e = f; | |
| 290 | \\// zig fmt: on | |
| 291 | \\// test1 | |
| 292 | \\/// test2 | |
| 293 | \\const e = f; | |
| 294 | \\ | |
| 295 | ); | |
| 296 | } | |
| 297 | ||
| 298 | test "zig fmt: doc and line comment following 'zig fmt: on'" { | |
| 299 | try testCanonical( | |
| 300 | \\// zig fmt: off | |
| 301 | \\const e = f; | |
| 302 | \\// zig fmt: on | |
| 303 | \\/// test1 | |
| 304 | \\// test2 | |
| 305 | \\const e = f; | |
| 306 | \\ | |
| 307 | ); | |
| 308 | } | |
| 309 | ||
| 213 | 310 | test "zig fmt: pointer of unknown length" { |
| 214 | 311 | try testCanonical( |
| 215 | 312 | \\fn foo(ptr: [*]u8) void {} |
| ... | ... | @@ -2278,7 +2375,6 @@ test "zig fmt: if type expr" { |
| 2278 | 2375 | \\ |
| 2279 | 2376 | ); |
| 2280 | 2377 | } |
| 2281 | ||
| 2282 | 2378 | test "zig fmt: file ends with struct field" { |
| 2283 | 2379 | try testTransform( |
| 2284 | 2380 | \\a: bool |
| ... | ... | @@ -2288,6 +2384,20 @@ test "zig fmt: file ends with struct field" { |
| 2288 | 2384 | ); |
| 2289 | 2385 | } |
| 2290 | 2386 | |
| 2387 | test "zig fmt: comment after empty comment" { | |
| 2388 | try testTransform( | |
| 2389 | \\const x = true; // | |
| 2390 | \\// | |
| 2391 | \\// | |
| 2392 | \\//a | |
| 2393 | \\ | |
| 2394 | , | |
| 2395 | \\const x = true; | |
| 2396 | \\//a | |
| 2397 | \\ | |
| 2398 | ); | |
| 2399 | } | |
| 2400 | ||
| 2291 | 2401 | test "zig fmt: comments at several places in struct init" { |
| 2292 | 2402 | try testTransform( |
| 2293 | 2403 | \\var bar = Bar{ |
std/zig/render.zig+101-35| ... | ... | @@ -89,41 +89,98 @@ fn renderRoot( |
| 89 | 89 | var it = tree.root_node.decls.iterator(0); |
| 90 | 90 | while (true) { |
| 91 | 91 | var decl = (it.next() orelse return).*; |
| 92 | // look for zig fmt: off comment | |
| 93 | var start_token_index = decl.firstToken(); | |
| 94 | zig_fmt_loop: while (start_token_index != 0) { | |
| 95 | start_token_index -= 1; | |
| 96 | const start_token = tree.tokens.at(start_token_index); | |
| 97 | switch (start_token.id) { | |
| 92 | ||
| 93 | // This loop does the following: | |
| 94 | // | |
| 95 | // - Iterates through line/doc comment tokens that precedes the current | |
| 96 | // decl. | |
| 97 | // - Figures out the first token index (`copy_start_token_index`) which | |
| 98 | // hasn't been copied to the output stream yet. | |
| 99 | // - Detects `zig fmt: (off|on)` in the line comment tokens, and | |
| 100 | // determines whether the current decl should be reformatted or not. | |
| 101 | // | |
| 102 | var token_index = decl.firstToken(); | |
| 103 | var fmt_active = true; | |
| 104 | var found_fmt_directive = false; | |
| 105 | ||
| 106 | var copy_start_token_index = token_index; | |
| 107 | ||
| 108 | while (token_index != 0) { | |
| 109 | token_index -= 1; | |
| 110 | const token = tree.tokens.at(token_index); | |
| 111 | switch (token.id) { | |
| 98 | 112 | Token.Id.LineComment => {}, |
| 99 | Token.Id.DocComment => continue, | |
| 113 | Token.Id.DocComment => { | |
| 114 | copy_start_token_index = token_index; | |
| 115 | continue; | |
| 116 | }, | |
| 100 | 117 | else => break, |
| 101 | 118 | } |
| 102 | if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(start_token)[2..], " "), "zig fmt: off")) { | |
| 103 | var end_token_index = start_token_index; | |
| 104 | while (true) { | |
| 105 | end_token_index += 1; | |
| 106 | const end_token = tree.tokens.at(end_token_index); | |
| 107 | switch (end_token.id) { | |
| 119 | ||
| 120 | if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: off")) { | |
| 121 | if (!found_fmt_directive) { | |
| 122 | fmt_active = false; | |
| 123 | found_fmt_directive = true; | |
| 124 | } | |
| 125 | } else if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: on")) { | |
| 126 | if (!found_fmt_directive) { | |
| 127 | fmt_active = true; | |
| 128 | found_fmt_directive = true; | |
| 129 | } | |
| 130 | } | |
| 131 | } | |
| 132 | ||
| 133 | if (!fmt_active) { | |
| 134 | // Reformatting is disabled for the current decl and possibly some | |
| 135 | // more decls that follow. | |
| 136 | // Find the next `decl` for which reformatting is re-enabled. | |
| 137 | token_index = decl.firstToken(); | |
| 138 | ||
| 139 | while (!fmt_active) { | |
| 140 | decl = (it.next() orelse { | |
| 141 | // If there's no next reformatted `decl`, just copy the | |
| 142 | // remaining input tokens and bail out. | |
| 143 | const start = tree.tokens.at(copy_start_token_index).start; | |
| 144 | try copyFixingWhitespace(stream, tree.source[start..]); | |
| 145 | return; | |
| 146 | }).*; | |
| 147 | var decl_first_token_index = decl.firstToken(); | |
| 148 | ||
| 149 | while (token_index < decl_first_token_index) : (token_index += 1) { | |
| 150 | const token = tree.tokens.at(token_index); | |
| 151 | switch (token.id) { | |
| 108 | 152 | Token.Id.LineComment => {}, |
| 109 | Token.Id.Eof => { | |
| 110 | const start = tree.tokens.at(start_token_index + 1).start; | |
| 111 | try copyFixingWhitespace(stream, tree.source[start..]); | |
| 112 | return; | |
| 113 | }, | |
| 153 | Token.Id.Eof => unreachable, | |
| 114 | 154 | else => continue, |
| 115 | 155 | } |
| 116 | if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(end_token)[2..], " "), "zig fmt: on")) { | |
| 117 | const start = tree.tokens.at(start_token_index + 1).start; | |
| 118 | try copyFixingWhitespace(stream, tree.source[start..end_token.end]); | |
| 119 | try stream.writeByte('\n'); | |
| 120 | while (tree.tokens.at(decl.firstToken()).start < end_token.end) { | |
| 121 | decl = (it.next() orelse return).*; | |
| 122 | } | |
| 123 | break :zig_fmt_loop; | |
| 156 | if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: on")) { | |
| 157 | fmt_active = true; | |
| 158 | } else if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: off")) { | |
| 159 | fmt_active = false; | |
| 124 | 160 | } |
| 125 | 161 | } |
| 126 | 162 | } |
| 163 | ||
| 164 | // Found the next `decl` for which reformatting is enabled. Copy | |
| 165 | // the input tokens before the `decl` that haven't been copied yet. | |
| 166 | var copy_end_token_index = decl.firstToken(); | |
| 167 | token_index = copy_end_token_index; | |
| 168 | while (token_index != 0) { | |
| 169 | token_index -= 1; | |
| 170 | const token = tree.tokens.at(token_index); | |
| 171 | switch (token.id) { | |
| 172 | Token.Id.LineComment => {}, | |
| 173 | Token.Id.DocComment => { | |
| 174 | copy_end_token_index = token_index; | |
| 175 | continue; | |
| 176 | }, | |
| 177 | else => break, | |
| 178 | } | |
| 179 | } | |
| 180 | ||
| 181 | const start = tree.tokens.at(copy_start_token_index).start; | |
| 182 | const end = tree.tokens.at(copy_end_token_index).start; | |
| 183 | try copyFixingWhitespace(stream, tree.source[start..end]); | |
| 127 | 184 | } |
| 128 | 185 | |
| 129 | 186 | try renderTopLevelDecl(allocator, stream, tree, 0, &start_col, decl); |
| ... | ... | @@ -1937,15 +1994,24 @@ fn renderTokenOffset( |
| 1937 | 1994 | } |
| 1938 | 1995 | } |
| 1939 | 1996 | |
| 1940 | const comment_is_empty = mem.trimRight(u8, tree.tokenSlicePtr(next_token), " ").len == 2; | |
| 1941 | if (comment_is_empty) { | |
| 1942 | switch (space) { | |
| 1943 | Space.Newline => { | |
| 1944 | try stream.writeByte('\n'); | |
| 1945 | start_col.* = 0; | |
| 1946 | return; | |
| 1947 | }, | |
| 1948 | else => {}, | |
| 1997 | while (true) { | |
| 1998 | const comment_is_empty = mem.trimRight(u8, tree.tokenSlicePtr(next_token), " ").len == 2; | |
| 1999 | if (comment_is_empty) { | |
| 2000 | switch (space) { | |
| 2001 | Space.Newline => { | |
| 2002 | offset += 1; | |
| 2003 | token = next_token; | |
| 2004 | next_token = tree.tokens.at(token_index + offset); | |
| 2005 | if (next_token.id != .LineComment) { | |
| 2006 | try stream.writeByte('\n'); | |
| 2007 | start_col.* = 0; | |
| 2008 | return; | |
| 2009 | } | |
| 2010 | }, | |
| 2011 | else => break, | |
| 2012 | } | |
| 2013 | } else { | |
| 2014 | break; | |
| 1949 | 2015 | } |
| 1950 | 2016 | } |
| 1951 | 2017 |
test/compile_errors.zig+4-4| ... | ... | @@ -273,7 +273,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 273 | 273 | \\} |
| 274 | 274 | , |
| 275 | 275 | "tmp.zig:1:1: error: function with calling convention 'ccc' cannot be async", |
| 276 | "tmp.zig:3:18: note: await is a suspend point", | |
| 276 | "tmp.zig:3:18: note: await here is a suspend point", | |
| 277 | 277 | ); |
| 278 | 278 | |
| 279 | 279 | cases.add( |
| ... | ... | @@ -507,11 +507,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 507 | 507 | |
| 508 | 508 | cases.add( |
| 509 | 509 | "@sizeOf bad type", |
| 510 | \\export fn entry() void { | |
| 511 | \\ _ = @sizeOf(@typeOf(null)); | |
| 510 | \\export fn entry() usize { | |
| 511 | \\ return @sizeOf(@typeOf(null)); | |
| 512 | 512 | \\} |
| 513 | 513 | , |
| 514 | "tmp.zig:2:17: error: no size available for type '(null)'", | |
| 514 | "tmp.zig:2:20: error: no size available for type '(null)'", | |
| 515 | 515 | ); |
| 516 | 516 | |
| 517 | 517 | cases.add( |
test/stage1/behavior/array.zig+6| ... | ... | @@ -292,3 +292,9 @@ test "read/write through global variable array of struct fields initialized via |
| 292 | 292 | }; |
| 293 | 293 | S.doTheTest(); |
| 294 | 294 | } |
| 295 | ||
| 296 | test "implicit cast zero sized array ptr to slice" { | |
| 297 | var b = ""; | |
| 298 | const c: []const u8 = &b; | |
| 299 | expect(c.len == 0); | |
| 300 | } |
test/stage1/behavior/async_fn.zig+10| ... | ... | @@ -844,3 +844,13 @@ test "cast fn to async fn when it is inferred to be async" { |
| 844 | 844 | resume S.frame; |
| 845 | 845 | expect(S.ok); |
| 846 | 846 | } |
| 847 | ||
| 848 | test "await does not force async if callee is blocking" { | |
| 849 | const S = struct { | |
| 850 | fn simple() i32 { | |
| 851 | return 1234; | |
| 852 | } | |
| 853 | }; | |
| 854 | var x = async S.simple(); | |
| 855 | expect(await x == 1234); | |
| 856 | } |
test/stage1/behavior/error.zig+20| ... | ... | @@ -375,3 +375,23 @@ test "implicit cast to optional to error union to return result loc" { |
| 375 | 375 | S.entry(); |
| 376 | 376 | //comptime S.entry(); TODO |
| 377 | 377 | } |
| 378 | ||
| 379 | test "function pointer with return type that is error union with payload which is pointer of parent struct" { | |
| 380 | const S = struct { | |
| 381 | const Foo = struct { | |
| 382 | fun: fn (a: i32) (anyerror!*Foo), | |
| 383 | }; | |
| 384 | ||
| 385 | const Err = error{UnspecifiedErr}; | |
| 386 | ||
| 387 | fn bar(a: i32) anyerror!*Foo { | |
| 388 | return Err.UnspecifiedErr; | |
| 389 | } | |
| 390 | ||
| 391 | fn doTheTest() void { | |
| 392 | var x = Foo{ .fun = bar }; | |
| 393 | expectError(error.UnspecifiedErr, x.fun(1)); | |
| 394 | } | |
| 395 | }; | |
| 396 | S.doTheTest(); | |
| 397 | } |
test/stage1/behavior/sizeof_and_typeof.zig+15| ... | ... | @@ -74,3 +74,18 @@ test "@sizeOf on compile-time types" { |
| 74 | 74 | expect(@sizeOf(@typeOf(.hi)) == 0); |
| 75 | 75 | expect(@sizeOf(@typeOf(type)) == 0); |
| 76 | 76 | } |
| 77 | ||
| 78 | test "@sizeOf(T) == 0 doesn't force resolving struct size" { | |
| 79 | const S = struct { | |
| 80 | const Foo = struct { | |
| 81 | y: if (@sizeOf(Foo) == 0) u64 else u32, | |
| 82 | }; | |
| 83 | const Bar = struct { | |
| 84 | x: i32, | |
| 85 | y: if (0 == @sizeOf(Bar)) u64 else u32, | |
| 86 | }; | |
| 87 | }; | |
| 88 | ||
| 89 | expect(@sizeOf(S.Foo) == 4); | |
| 90 | expect(@sizeOf(S.Bar) == 8); | |
| 91 | } |