authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-29 22:44:21-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-29 22:44:21-04:00
log10541c8fc88875cb51df0a5fdeda20847133e676
tree1c8b6c29b99f0cc7f22307674dd58634b1910d12
parent94bbb46ca602be0ea0df97c207a98734ac459a0f
parente9a4bcbcc6ac89c5526a6baaf2b0df49d0577eb4
signaturelock-open Commit is signed but in an unrecognized format.

Merge branch 'lazy-sizeof'


11 files changed, 463 insertions(+), 141 deletions(-)

src/all_types.hpp+12
...@@ -36,6 +36,7 @@ struct IrInstruction;...@@ -36,6 +36,7 @@ struct IrInstruction;
36struct IrInstructionCast;36struct IrInstructionCast;
37struct IrInstructionAllocaGen;37struct IrInstructionAllocaGen;
38struct IrInstructionCallGen;38struct IrInstructionCallGen;
39struct IrInstructionAwaitGen;
39struct IrBasicBlock;40struct IrBasicBlock;
40struct ScopeDecls;41struct ScopeDecls;
41struct ZigWindowsSDK;42struct ZigWindowsSDK;
...@@ -308,6 +309,7 @@ struct ConstGlobalRefs {...@@ -308,6 +309,7 @@ struct ConstGlobalRefs {
308enum LazyValueId {309enum LazyValueId {
309 LazyValueIdInvalid,310 LazyValueIdInvalid,
310 LazyValueIdAlignOf,311 LazyValueIdAlignOf,
312 LazyValueIdSizeOf,
311 LazyValueIdPtrType,313 LazyValueIdPtrType,
312 LazyValueIdOptType,314 LazyValueIdOptType,
313 LazyValueIdSliceType,315 LazyValueIdSliceType,
...@@ -326,6 +328,13 @@ struct LazyValueAlignOf {...@@ -326,6 +328,13 @@ struct LazyValueAlignOf {
326 IrInstruction *target_type;328 IrInstruction *target_type;
327};329};
328330
331struct LazyValueSizeOf {
332 LazyValue base;
333
334 IrAnalyze *ira;
335 IrInstruction *target_type;
336};
337
329struct LazyValueSliceType {338struct LazyValueSliceType {
330 LazyValue base;339 LazyValue base;
331340
...@@ -1478,6 +1487,7 @@ struct ZigFn {...@@ -1478,6 +1487,7 @@ struct ZigFn {
1478 AstNode **param_source_nodes;1487 AstNode **param_source_nodes;
1479 Buf **param_names;1488 Buf **param_names;
1480 IrInstruction *err_code_spill;1489 IrInstruction *err_code_spill;
1490 AstNode *assumed_non_async;
14811491
1482 AstNode *fn_no_inline_set_node;1492 AstNode *fn_no_inline_set_node;
1483 AstNode *fn_static_eval_set_node;1493 AstNode *fn_static_eval_set_node;
...@@ -1495,6 +1505,7 @@ struct ZigFn {...@@ -1495,6 +1505,7 @@ struct ZigFn {
14951505
1496 ZigList<GlobalExport> export_list;1506 ZigList<GlobalExport> export_list;
1497 ZigList<IrInstructionCallGen *> call_list;1507 ZigList<IrInstructionCallGen *> call_list;
1508 ZigList<IrInstructionAwaitGen *> await_list;
14981509
1499 LLVMValueRef valgrind_client_request_array;1510 LLVMValueRef valgrind_client_request_array;
15001511
...@@ -3709,6 +3720,7 @@ struct IrInstructionAwaitGen {...@@ -3709,6 +3720,7 @@ struct IrInstructionAwaitGen {
37093720
3710 IrInstruction *frame;3721 IrInstruction *frame;
3711 IrInstruction *result_loc;3722 IrInstruction *result_loc;
3723 ZigFn *target_fn;
3712};3724};
37133725
3714struct IrInstructionResume {3726struct IrInstructionResume {
src/analyze.cpp+142-37
...@@ -31,6 +31,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry);...@@ -31,6 +31,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry);
31static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status);31static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status);
32static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope);32static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope);
33static void resolve_use_decl(CodeGen *g, TldUsingNamespace *tld_using_namespace, ScopeDecls *dest_decls_scope);33static void resolve_use_decl(CodeGen *g, TldUsingNamespace *tld_using_namespace, ScopeDecls *dest_decls_scope);
34static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame);
3435
35// nullptr means not analyzed yet; this one means currently being analyzed36// nullptr means not analyzed yet; this one means currently being analyzed
36static const AstNode *inferred_async_checking = reinterpret_cast<AstNode *>(0x1);37static 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,7 +974,7 @@ ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, Zig
973 nullptr, nullptr, node, type_name, nullptr, nullptr, undef);974 nullptr, nullptr, node, type_name, nullptr, nullptr, undef);
974}975}
975976
976static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, ZigType *parent_type,977Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, ZigType *parent_type,
977 ConstExprValue *parent_type_val, bool *is_zero_bits)978 ConstExprValue *parent_type_val, bool *is_zero_bits)
978{979{
979 Error err;980 Error err;
...@@ -997,6 +998,7 @@ static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, Zi...@@ -997,6 +998,7 @@ static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, Zi
997 switch (type_val->data.x_lazy->id) {998 switch (type_val->data.x_lazy->id) {
998 case LazyValueIdInvalid:999 case LazyValueIdInvalid:
999 case LazyValueIdAlignOf:1000 case LazyValueIdAlignOf:
1001 case LazyValueIdSizeOf:
1000 zig_unreachable();1002 zig_unreachable();
1001 case LazyValueIdPtrType: {1003 case LazyValueIdPtrType: {
1002 LazyValuePtrType *lazy_ptr_type = reinterpret_cast<LazyValuePtrType *>(type_val->data.x_lazy);1004 LazyValuePtrType *lazy_ptr_type = reinterpret_cast<LazyValuePtrType *>(type_val->data.x_lazy);
...@@ -1036,6 +1038,7 @@ Error type_val_resolve_is_opaque_type(CodeGen *g, ConstExprValue *type_val, bool...@@ -1036,6 +1038,7 @@ Error type_val_resolve_is_opaque_type(CodeGen *g, ConstExprValue *type_val, bool
1036 switch (type_val->data.x_lazy->id) {1038 switch (type_val->data.x_lazy->id) {
1037 case LazyValueIdInvalid:1039 case LazyValueIdInvalid:
1038 case LazyValueIdAlignOf:1040 case LazyValueIdAlignOf:
1041 case LazyValueIdSizeOf:
1039 zig_unreachable();1042 zig_unreachable();
1040 case LazyValueIdSliceType:1043 case LazyValueIdSliceType:
1041 case LazyValueIdPtrType:1044 case LazyValueIdPtrType:
...@@ -1055,6 +1058,7 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue...@@ -1055,6 +1058,7 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue
1055 switch (type_val->data.x_lazy->id) {1058 switch (type_val->data.x_lazy->id) {
1056 case LazyValueIdInvalid:1059 case LazyValueIdInvalid:
1057 case LazyValueIdAlignOf:1060 case LazyValueIdAlignOf:
1061 case LazyValueIdSizeOf:
1058 zig_unreachable();1062 zig_unreachable();
1059 case LazyValueIdSliceType: {1063 case LazyValueIdSliceType: {
1060 LazyValueSliceType *lazy_slice_type = reinterpret_cast<LazyValueSliceType *>(type_val->data.x_lazy);1064 LazyValueSliceType *lazy_slice_type = reinterpret_cast<LazyValueSliceType *>(type_val->data.x_lazy);
...@@ -1105,7 +1109,7 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue...@@ -1105,7 +1109,7 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue
1105 zig_unreachable();1109 zig_unreachable();
1106}1110}
11071111
1108static Error type_val_resolve_abi_size(CodeGen *g, AstNode *source_node, ConstExprValue *type_val,1112Error type_val_resolve_abi_size(CodeGen *g, AstNode *source_node, ConstExprValue *type_val,
1109 size_t *abi_size, size_t *size_in_bits)1113 size_t *abi_size, size_t *size_in_bits)
1110{1114{
1111 Error err;1115 Error err;
...@@ -1123,12 +1127,42 @@ start_over:...@@ -1123,12 +1127,42 @@ start_over:
1123 switch (type_val->data.x_lazy->id) {1127 switch (type_val->data.x_lazy->id) {
1124 case LazyValueIdInvalid:1128 case LazyValueIdInvalid:
1125 case LazyValueIdAlignOf:1129 case LazyValueIdAlignOf:
1130 case LazyValueIdSizeOf:
1126 zig_unreachable();1131 zig_unreachable();
1127 case LazyValueIdSliceType:1132 case LazyValueIdSliceType: {
1128 *abi_size = g->builtin_types.entry_usize->abi_size * 2;1133 LazyValueSliceType *lazy_slice_type = reinterpret_cast<LazyValueSliceType *>(type_val->data.x_lazy);
1129 *size_in_bits = g->builtin_types.entry_usize->size_in_bits * 2;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 }
1130 return ErrorNone;1147 return ErrorNone;
1131 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 }
1132 case LazyValueIdFnType:1166 case LazyValueIdFnType:
1133 *abi_size = g->builtin_types.entry_usize->abi_size;1167 *abi_size = g->builtin_types.entry_usize->abi_size;
1134 *size_in_bits = g->builtin_types.entry_usize->size_in_bits;1168 *size_in_bits = g->builtin_types.entry_usize->size_in_bits;
...@@ -1159,6 +1193,7 @@ Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, uint32_t...@@ -1159,6 +1193,7 @@ Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, uint32_t
1159 switch (type_val->data.x_lazy->id) {1193 switch (type_val->data.x_lazy->id) {
1160 case LazyValueIdInvalid:1194 case LazyValueIdInvalid:
1161 case LazyValueIdAlignOf:1195 case LazyValueIdAlignOf:
1196 case LazyValueIdSizeOf:
1162 zig_unreachable();1197 zig_unreachable();
1163 case LazyValueIdSliceType:1198 case LazyValueIdSliceType:
1164 case LazyValueIdPtrType:1199 case LazyValueIdPtrType:
...@@ -1193,6 +1228,7 @@ static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, Cons...@@ -1193,6 +1228,7 @@ static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, Cons
1193 switch (type_val->data.x_lazy->id) {1228 switch (type_val->data.x_lazy->id) {
1194 case LazyValueIdInvalid:1229 case LazyValueIdInvalid:
1195 case LazyValueIdAlignOf:1230 case LazyValueIdAlignOf:
1231 case LazyValueIdSizeOf:
1196 zig_unreachable();1232 zig_unreachable();
1197 case LazyValueIdSliceType: // it has the len field1233 case LazyValueIdSliceType: // it has the len field
1198 case LazyValueIdOptType: // it has the optional bit1234 case LazyValueIdOptType: // it has the optional bit
...@@ -4138,8 +4174,14 @@ static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) {...@@ -4138,8 +4174,14 @@ static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) {
4138 assert(fn->inferred_async_node != inferred_async_checking);4174 assert(fn->inferred_async_node != inferred_async_checking);
4139 assert(fn->inferred_async_node != inferred_async_none);4175 assert(fn->inferred_async_node != inferred_async_none);
4140 if (fn->inferred_async_fn != nullptr) {4176 if (fn->inferred_async_fn != nullptr) {
4141 ErrorMsg *new_msg = add_error_note(g, msg, fn->inferred_async_node,4177 ErrorMsg *new_msg;
4142 buf_sprintf("async function call here"));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 }
4143 return add_async_error_notes(g, new_msg, fn->inferred_async_fn);4185 return add_async_error_notes(g, new_msg, fn->inferred_async_fn);
4144 } else if (fn->inferred_async_node->type == NodeTypeFnProto) {4186 } else if (fn->inferred_async_node->type == NodeTypeFnProto) {
4145 add_error_note(g, msg, fn->inferred_async_node,4187 add_error_note(g, msg, fn->inferred_async_node,
...@@ -4149,7 +4191,7 @@ static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) {...@@ -4149,7 +4191,7 @@ static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) {
4149 buf_sprintf("suspends here"));4191 buf_sprintf("suspends here"));
4150 } else if (fn->inferred_async_node->type == NodeTypeAwaitExpr) {4192 } else if (fn->inferred_async_node->type == NodeTypeAwaitExpr) {
4151 add_error_note(g, msg, fn->inferred_async_node,4193 add_error_note(g, msg, fn->inferred_async_node,
4152 buf_sprintf("await is a suspend point"));4194 buf_sprintf("await here is a suspend point"));
4153 } else if (fn->inferred_async_node->type == NodeTypeFnCallExpr &&4195 } else if (fn->inferred_async_node->type == NodeTypeFnCallExpr &&
4154 fn->inferred_async_node->data.fn_call_expr.is_builtin)4196 fn->inferred_async_node->data.fn_call_expr.is_builtin)
4155 {4197 {
...@@ -4161,6 +4203,64 @@ static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) {...@@ -4161,6 +4203,64 @@ static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) {
4161 }4203 }
4162}4204}
41634205
4206// ErrorNone - not async
4207// ErrorIsAsync - yes async
4208// ErrorSemanticAnalyzeFail - compile error emitted result is invalid
4209static 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
4164// This function resolves functions being inferred async.4264// This function resolves functions being inferred async.
4165static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) {4265static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) {
4166 if (fn->inferred_async_node == inferred_async_checking) {4266 if (fn->inferred_async_node == inferred_async_checking) {
...@@ -4187,42 +4287,40 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) {...@@ -4187,42 +4287,40 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) {
41874287
4188 for (size_t i = 0; i < fn->call_list.length; i += 1) {4288 for (size_t i = 0; i < fn->call_list.length; i += 1) {
4189 IrInstructionCallGen *call = fn->call_list.at(i);4289 IrInstructionCallGen *call = fn->call_list.at(i);
4190 ZigFn *callee = call->fn_entry;4290 if (call->fn_entry == nullptr) {
4191 if (callee == nullptr) {
4192 // TODO function pointer call here, could be anything4291 // TODO function pointer call here, could be anything
4193 continue;4292 continue;
4194 }4293 }
41954294 switch (analyze_callee_async(g, fn, call->fn_entry, call->base.source_node, must_not_be_async)) {
4196 if (callee->type_entry->data.fn.fn_type_id.cc != CallingConventionUnspecified)4295 case ErrorSemanticAnalyzeFail:
4197 continue;
4198 if (callee->anal_state == FnAnalStateReady) {
4199 analyze_fn_body(g, callee);
4200 if (callee->anal_state == FnAnalStateInvalid) {
4201 fn->anal_state = FnAnalStateInvalid;4296 fn->anal_state = FnAnalStateInvalid;
4202 return;4297 return;
4203 }4298 case ErrorNone:
4204 }4299 continue;
4205 assert(callee->anal_state == FnAnalStateComplete);4300 case ErrorIsAsync:
4206 analyze_fn_async(g, callee, true);4301 if (resolve_frame) {
4207 if (callee->anal_state == FnAnalStateInvalid) {4302 resolve_async_fn_frame(g, fn);
4208 fn->anal_state = FnAnalStateInvalid;4303 }
4209 return;4304 return;
4305 default:
4306 zig_unreachable();
4210 }4307 }
4211 if (fn_is_async(callee)) {4308 }
4212 fn->inferred_async_node = call->base.source_node;4309 for (size_t i = 0; i < fn->await_list.length; i += 1) {
4213 fn->inferred_async_fn = callee;4310 IrInstructionAwaitGen *await = fn->await_list.at(i);
4214 if (must_not_be_async) {4311 switch (analyze_callee_async(g, fn, await->target_fn, await->base.source_node, must_not_be_async)) {
4215 ErrorMsg *msg = add_node_error(g, fn->proto_node,4312 case ErrorSemanticAnalyzeFail:
4216 buf_sprintf("function with calling convention '%s' cannot be async",
4217 calling_convention_name(fn->type_entry->data.fn.fn_type_id.cc)));
4218 add_async_error_notes(g, msg, fn);
4219 fn->anal_state = FnAnalStateInvalid;4313 fn->anal_state = FnAnalStateInvalid;
4220 return;4314 return;
4221 }4315 case ErrorNone:
4222 if (resolve_frame) {4316 continue;
4223 resolve_async_fn_frame(g, fn);4317 case ErrorIsAsync:
4224 }4318 if (resolve_frame) {
4225 return;4319 resolve_async_fn_frame(g, fn);
4320 }
4321 return;
4322 default:
4323 zig_unreachable();
4226 }4324 }
4227 }4325 }
4228 fn->inferred_async_node = inferred_async_none;4326 fn->inferred_async_node = inferred_async_none;
...@@ -4480,6 +4578,8 @@ void semantic_analyze(CodeGen *g) {...@@ -4480,6 +4578,8 @@ void semantic_analyze(CodeGen *g) {
4480 ZigFn *fn = g->fn_defs.at(g->fn_defs_index);4578 ZigFn *fn = g->fn_defs.at(g->fn_defs_index);
4481 g->trace_err = nullptr;4579 g->trace_err = nullptr;
4482 analyze_fn_async(g, fn, true);4580 analyze_fn_async(g, fn, true);
4581 if (fn->anal_state == FnAnalStateInvalid)
4582 continue;
4483 if (fn_is_async(fn) && fn->non_async_node != nullptr) {4583 if (fn_is_async(fn) && fn->non_async_node != nullptr) {
4484 ErrorMsg *msg = add_node_error(g, fn->proto_node,4584 ErrorMsg *msg = add_node_error(g, fn->proto_node,
4485 buf_sprintf("'%s' cannot be async", buf_ptr(&fn->symbol_name)));4585 buf_sprintf("'%s' cannot be async", buf_ptr(&fn->symbol_name)));
...@@ -5632,6 +5732,11 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {...@@ -5632,6 +5732,11 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
5632 return ErrorSemanticAnalyzeFail;5732 return ErrorSemanticAnalyzeFail;
5633 }5733 }
5634 analyze_fn_async(g, callee, true);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 }
5635 if (!fn_is_async(callee))5740 if (!fn_is_async(callee))
5636 continue;5741 continue;
56375742
src/analyze.hpp+4
...@@ -247,6 +247,10 @@ void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn);...@@ -247,6 +247,10 @@ void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn);
247bool fn_is_async(ZigFn *fn);247bool fn_is_async(ZigFn *fn);
248248
249Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, uint32_t *abi_align);249Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, uint32_t *abi_align);
250Error type_val_resolve_abi_size(CodeGen *g, AstNode *source_node, ConstExprValue *type_val,
251 size_t *abi_size, size_t *size_in_bits);
252Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, ZigType *parent_type,
253 ConstExprValue *parent_type_val, bool *is_zero_bits);
250ZigType *resolve_union_field_type(CodeGen *g, TypeUnionField *union_field);254ZigType *resolve_union_field_type(CodeGen *g, TypeUnionField *union_field);
251ZigType *resolve_struct_field_type(CodeGen *g, TypeStructField *struct_field);255ZigType *resolve_struct_field_type(CodeGen *g, TypeStructField *struct_field);
252256
src/codegen.cpp+58-25
...@@ -3924,7 +3924,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -3924,7 +3924,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
3924 LLVMBuildStore(g->builder, awaiter_init_val, awaiter_ptr);3924 LLVMBuildStore(g->builder, awaiter_init_val, awaiter_ptr);
39253925
3926 if (ret_has_bits) {3926 if (ret_has_bits) {
3927 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, "");
3928 LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start, "");3928 LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start, "");
3929 LLVMBuildStore(g->builder, ret_ptr, ret_ptr_ptr);3929 LLVMBuildStore(g->builder, ret_ptr, ret_ptr_ptr);
39303930
...@@ -4067,6 +4067,9 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -4067,6 +4067,9 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
4067 LLVMValueRef store_instr = LLVMBuildStore(g->builder, result, result_loc);4067 LLVMValueRef store_instr = LLVMBuildStore(g->builder, result, result_loc);
4068 LLVMSetAlignment(store_instr, get_ptr_align(g, instruction->result_loc->value.type));4068 LLVMSetAlignment(store_instr, get_ptr_align(g, instruction->result_loc->value.type));
4069 return result_loc;4069 return result_loc;
4070 } else if (!callee_is_async && instruction->is_async) {
4071 LLVMBuildStore(g->builder, result, ret_ptr);
4072 return result_loc;
4070 } else {4073 } else {
4071 return result;4074 return result;
4072 }4075 }
...@@ -5498,6 +5501,44 @@ static LLVMValueRef ir_render_suspend_finish(CodeGen *g, IrExecutable *executabl...@@ -5498,6 +5501,44 @@ static LLVMValueRef ir_render_suspend_finish(CodeGen *g, IrExecutable *executabl
5498 return nullptr;5501 return nullptr;
5499}5502}
55005503
5504static 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
5501static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInstructionAwaitGen *instruction) {5542static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInstructionAwaitGen *instruction) {
5502 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;5543 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
5503 LLVMValueRef zero = LLVMConstNull(usize_type_ref);5544 LLVMValueRef zero = LLVMConstNull(usize_type_ref);
...@@ -5505,6 +5546,14 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInst...@@ -5505,6 +5546,14 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInst
5505 ZigType *result_type = instruction->base.value.type;5546 ZigType *result_type = instruction->base.value.type;
5506 ZigType *ptr_result_type = get_pointer_to_type(g, result_type, true);5547 ZigType *ptr_result_type = get_pointer_to_type(g, result_type, true);
55075548
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
5508 // Prepare to be suspended5557 // Prepare to be suspended
5509 LLVMBasicBlockRef resume_bb = gen_suspend_begin(g, "AwaitResume");5558 LLVMBasicBlockRef resume_bb = gen_suspend_begin(g, "AwaitResume");
5510 LLVMBasicBlockRef end_bb = LLVMAppendBasicBlock(g->cur_fn_val, "AwaitEnd");5559 LLVMBasicBlockRef end_bb = LLVMAppendBasicBlock(g->cur_fn_val, "AwaitEnd");
...@@ -5512,9 +5561,8 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInst...@@ -5512,9 +5561,8 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInst
5512 // At this point resuming the function will continue from resume_bb.5561 // At this point resuming the function will continue from resume_bb.
5513 // This code is as if it is running inside the suspend block.5562 // This code is as if it is running inside the suspend block.
55145563
5564
5515 // supply the awaiter return pointer5565 // supply the awaiter return pointer
5516 LLVMValueRef result_loc = (instruction->result_loc == nullptr) ?
5517 nullptr : ir_llvm_value(g, instruction->result_loc);
5518 if (type_has_bits(result_type)) {5566 if (type_has_bits(result_type)) {
5519 LLVMValueRef awaiter_ret_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, frame_ret_start + 1, "");5567 LLVMValueRef awaiter_ret_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, frame_ret_start + 1, "");
5520 if (result_loc == nullptr) {5568 if (result_loc == nullptr) {
...@@ -5562,28 +5610,8 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInst...@@ -5562,28 +5610,8 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInst
5562 // Early return: The async function has already completed. We must copy the result and5610 // Early return: The async function has already completed. We must copy the result and
5563 // the error return trace if applicable.5611 // the error return trace if applicable.
5564 LLVMPositionBuilderAtEnd(g->builder, early_return_block);5612 LLVMPositionBuilderAtEnd(g->builder, early_return_block);
5565 if (type_has_bits(result_type) && result_loc != nullptr) {5613 gen_await_early_return(g, &instruction->base, target_frame_ptr, result_type, ptr_result_type,
5566 LLVMValueRef their_result_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, frame_ret_start, "");5614 result_loc, false);
5567 LLVMValueRef their_result_ptr = LLVMBuildLoad(g->builder, their_result_ptr_ptr, "");
5568 LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
5569 LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, result_loc, ptr_u8, "");
5570 LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, their_result_ptr, ptr_u8, "");
5571 bool is_volatile = false;
5572 uint32_t abi_align = get_abi_alignment(g, result_type);
5573 LLVMValueRef byte_count_val = LLVMConstInt(usize_type_ref, type_size(g, result_type), false);
5574 ZigLLVMBuildMemCpy(g->builder,
5575 dest_ptr_casted, abi_align,
5576 src_ptr_casted, abi_align, byte_count_val, is_volatile);
5577 }
5578 if (codegen_fn_has_err_ret_tracing_arg(g, result_type)) {
5579 LLVMValueRef their_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr,
5580 frame_index_trace_arg(g, result_type), "");
5581 LLVMValueRef src_trace_ptr = LLVMBuildLoad(g->builder, their_trace_ptr_ptr, "");
5582 LLVMValueRef dest_trace_ptr = get_cur_err_ret_trace_val(g, instruction->base.scope);
5583 LLVMValueRef args[] = { dest_trace_ptr, src_trace_ptr };
5584 ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2,
5585 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
5586 }
5587 LLVMBuildBr(g->builder, end_bb);5615 LLVMBuildBr(g->builder, end_bb);
55885616
5589 LLVMPositionBuilderAtEnd(g->builder, resume_bb);5617 LLVMPositionBuilderAtEnd(g->builder, resume_bb);
...@@ -6845,6 +6873,7 @@ static void set_global_tls(CodeGen *g, ZigVar *var, LLVMValueRef global_value) {...@@ -6845,6 +6873,7 @@ static void set_global_tls(CodeGen *g, ZigVar *var, LLVMValueRef global_value) {
6845}6873}
68466874
6847static void do_code_gen(CodeGen *g) {6875static void do_code_gen(CodeGen *g) {
6876 Error err;
6848 assert(!g->errors.length);6877 assert(!g->errors.length);
68496878
6850 generate_error_name_table(g);6879 generate_error_name_table(g);
...@@ -6858,6 +6887,8 @@ static void do_code_gen(CodeGen *g) {...@@ -6858,6 +6887,8 @@ static void do_code_gen(CodeGen *g) {
6858 // Generate debug info for it but that's it.6887 // Generate debug info for it but that's it.
6859 ConstExprValue *const_val = var->const_value;6888 ConstExprValue *const_val = var->const_value;
6860 assert(const_val->special != ConstValSpecialRuntime);6889 assert(const_val->special != ConstValSpecialRuntime);
6890 if ((err = ir_resolve_lazy(g, var->decl_node, const_val)))
6891 zig_unreachable();
6861 if (const_val->type != var->var_type) {6892 if (const_val->type != var->var_type) {
6862 zig_panic("TODO debug info for var with ptr casted value");6893 zig_panic("TODO debug info for var with ptr casted value");
6863 }6894 }
...@@ -6875,6 +6906,8 @@ static void do_code_gen(CodeGen *g) {...@@ -6875,6 +6906,8 @@ static void do_code_gen(CodeGen *g) {
6875 // Generate debug info for it but that's it.6906 // Generate debug info for it but that's it.
6876 ConstExprValue *const_val = var->const_value;6907 ConstExprValue *const_val = var->const_value;
6877 assert(const_val->special != ConstValSpecialRuntime);6908 assert(const_val->special != ConstValSpecialRuntime);
6909 if ((err = ir_resolve_lazy(g, var->decl_node, const_val)))
6910 zig_unreachable();
6878 if (const_val->type != var->var_type) {6911 if (const_val->type != var->var_type) {
6879 zig_panic("TODO debug info for var with ptr casted value");6912 zig_panic("TODO debug info for var with ptr casted value");
6880 }6913 }
src/error.cpp+2
...@@ -55,6 +55,8 @@ const char *err_str(Error err) {...@@ -55,6 +55,8 @@ const char *err_str(Error err) {
55 case ErrorBrokenPipe: return "broken pipe";55 case ErrorBrokenPipe: return "broken pipe";
56 case ErrorNoSpaceLeft: return "no space left";56 case ErrorNoSpaceLeft: return "no space left";
57 case ErrorNoCCompilerInstalled: return "no C compiler installed";57 case ErrorNoCCompilerInstalled: return "no C compiler installed";
58 case ErrorNotLazy: return "not lazy";
59 case ErrorIsAsync: return "is async";
58 }60 }
59 return "(invalid error)";61 return "(invalid error)";
60}62}
src/ir.cpp+208-70
...@@ -3268,7 +3268,7 @@ static IrInstruction *ir_build_await_src(IrBuilder *irb, Scope *scope, AstNode *...@@ -3268,7 +3268,7 @@ static IrInstruction *ir_build_await_src(IrBuilder *irb, Scope *scope, AstNode *
3268 return &instruction->base;3268 return &instruction->base;
3269}3269}
32703270
3271static IrInstruction *ir_build_await_gen(IrAnalyze *ira, IrInstruction *source_instruction,3271static IrInstructionAwaitGen *ir_build_await_gen(IrAnalyze *ira, IrInstruction *source_instruction,
3272 IrInstruction *frame, ZigType *result_type, IrInstruction *result_loc)3272 IrInstruction *frame, ZigType *result_type, IrInstruction *result_loc)
3273{3273{
3274 IrInstructionAwaitGen *instruction = ir_build_instruction<IrInstructionAwaitGen>(&ira->new_irb,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,7 +3280,7 @@ static IrInstruction *ir_build_await_gen(IrAnalyze *ira, IrInstruction *source_i
3280 ir_ref_instruction(frame, ira->new_irb.current_basic_block);3280 ir_ref_instruction(frame, ira->new_irb.current_basic_block);
3281 if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block);3281 if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block);
32823282
3283 return &instruction->base;3283 return instruction;
3284}3284}
32853285
3286static IrInstruction *ir_build_resume(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *frame) {3286static 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,7 +10640,9 @@ static void ir_finish_bb(IrAnalyze *ira) {
1064010640
10641static IrInstruction *ir_unreach_error(IrAnalyze *ira) {10641static IrInstruction *ir_unreach_error(IrAnalyze *ira) {
10642 ira->old_bb_index = SIZE_MAX;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 return ira->codegen->unreach_instruction;10646 return ira->codegen->unreach_instruction;
10645}10647}
1064610648
...@@ -12932,7 +12934,52 @@ static bool optional_value_is_null(ConstExprValue *val) {...@@ -12932,7 +12934,52 @@ static bool optional_value_is_null(ConstExprValue *val) {
12932 }12934 }
12933}12935}
1293412936
12937// Returns ErrorNotLazy when the value cannot be determined
12938static 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
12935static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {12980static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
12981 Error err;
12982
12936 IrInstruction *op1 = bin_op_instruction->op1->child;12983 IrInstruction *op1 = bin_op_instruction->op1->child;
12937 if (type_is_invalid(op1->value.type))12984 if (type_is_invalid(op1->value.type))
12938 return ira->codegen->invalid_instruction;12985 return ira->codegen->invalid_instruction;
...@@ -13182,6 +13229,50 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *...@@ -13182,6 +13229,50 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
13182 }13229 }
1318313230
13184 if (one_possible_value || (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2))) {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 }
13274never_mind_just_calculate_it_normally:
13275
13185 ConstExprValue *op1_val = one_possible_value ? &casted_op1->value : ir_resolve_const(ira, casted_op1, UndefBad);13276 ConstExprValue *op1_val = one_possible_value ? &casted_op1->value : ir_resolve_const(ira, casted_op1, UndefBad);
13186 if (op1_val == nullptr)13277 if (op1_val == nullptr)
13187 return ira->codegen->invalid_instruction;13278 return ira->codegen->invalid_instruction;
...@@ -16810,12 +16901,6 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct...@@ -16810,12 +16901,6 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
16810 return ira->codegen->invalid_instruction;16901 return ira->codegen->invalid_instruction;
1681116902
16812 bool safety_check_on = elem_ptr_instruction->safety_check_on;16903 bool safety_check_on = elem_ptr_instruction->safety_check_on;
16813 if ((err = type_resolve(ira->codegen, return_type->data.pointer.child_type, ResolveStatusSizeKnown)))
16814 return ira->codegen->invalid_instruction;
16815
16816 uint64_t elem_size = type_size(ira->codegen, return_type->data.pointer.child_type);
16817 uint64_t abi_align = get_abi_alignment(ira->codegen, return_type->data.pointer.child_type);
16818 uint64_t ptr_align = get_ptr_align(ira->codegen, return_type);
16819 if (instr_is_comptime(casted_elem_index)) {16904 if (instr_is_comptime(casted_elem_index)) {
16820 uint64_t index = bigint_as_u64(&casted_elem_index->value.data.x_bigint);16905 uint64_t index = bigint_as_u64(&casted_elem_index->value.data.x_bigint);
16821 if (array_type->id == ZigTypeIdArray) {16906 if (array_type->id == ZigTypeIdArray) {
...@@ -16829,8 +16914,16 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct...@@ -16829,8 +16914,16 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
16829 safety_check_on = false;16914 safety_check_on = false;
16830 }16915 }
1683116916
16832 {16917 if (return_type->data.pointer.explicit_alignment != 0) {
16833 // figure out the largest alignment possible16918 // 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
16834 uint64_t chosen_align = abi_align;16927 uint64_t chosen_align = abi_align;
16835 if (ptr_align >= abi_align) {16928 if (ptr_align >= abi_align) {
16836 while (ptr_align > abi_align) {16929 while (ptr_align > abi_align) {
...@@ -17059,15 +17152,24 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct...@@ -17059,15 +17152,24 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
17059 case ReqCompTimeNo:17152 case ReqCompTimeNo:
17060 break;17153 break;
17061 }17154 }
17062 if (ptr_align < abi_align) {17155
17063 if (elem_size >= ptr_align && elem_size % ptr_align == 0) {17156 if (return_type->data.pointer.explicit_alignment != 0) {
17064 return_type = adjust_ptr_align(ira->codegen, return_type, ptr_align);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 }
17065 } else {17170 } else {
17066 // can't get here because guaranteed elem_size >= abi_align17171 return_type = adjust_ptr_align(ira->codegen, return_type, abi_align);
17067 zig_unreachable();
17068 }17172 }
17069 } else {
17070 return_type = adjust_ptr_align(ira->codegen, return_type, abi_align);
17071 }17173 }
17072 }17174 }
1707317175
...@@ -18066,54 +18168,20 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,...@@ -18066,54 +18168,20 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,
18066 zig_unreachable();18168 zig_unreachable();
18067}18169}
1806818170
18069static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira,18171static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, IrInstructionSizeOf *instruction) {
18070 IrInstructionSizeOf *size_of_instruction)18172 IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_num_lit_int);
18071{18173 result->value.special = ConstValSpecialLazy;
18072 Error err;
18073 IrInstruction *type_value = size_of_instruction->type_value->child;
18074 ZigType *type_entry = ir_resolve_type(ira, type_value);
1807518174
18076 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)
18077 return ira->codegen->invalid_instruction;18182 return ira->codegen->invalid_instruction;
1807818183
18079 switch (type_entry->id) {18184 return result;
18080 case ZigTypeIdInvalid: // handled above
18081 zig_unreachable();
18082 case ZigTypeIdUnreachable:
18083 case ZigTypeIdUndefined:
18084 case ZigTypeIdNull:
18085 case ZigTypeIdBoundFn:
18086 case ZigTypeIdArgTuple:
18087 case ZigTypeIdOpaque:
18088 ir_add_error_node(ira, type_value->source_node,
18089 buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name)));
18090 return ira->codegen->invalid_instruction;
18091 case ZigTypeIdMetaType:
18092 case ZigTypeIdEnumLiteral:
18093 case ZigTypeIdComptimeFloat:
18094 case ZigTypeIdComptimeInt:
18095 case ZigTypeIdVoid:
18096 case ZigTypeIdBool:
18097 case ZigTypeIdInt:
18098 case ZigTypeIdFloat:
18099 case ZigTypeIdPointer:
18100 case ZigTypeIdArray:
18101 case ZigTypeIdStruct:
18102 case ZigTypeIdOptional:
18103 case ZigTypeIdErrorUnion:
18104 case ZigTypeIdErrorSet:
18105 case ZigTypeIdEnum:
18106 case ZigTypeIdUnion:
18107 case ZigTypeIdFn:
18108 case ZigTypeIdVector:
18109 case ZigTypeIdFnFrame:
18110 case ZigTypeIdAnyFrame:
18111 {
18112 uint64_t size_in_bytes = type_size(ira->codegen, type_entry);
18113 return ir_const_unsigned(ira, &size_of_instruction->base, size_in_bytes);
18114 }
18115 }
18116 zig_unreachable();
18117}18185}
1811818186
18119static IrInstruction *ir_analyze_test_non_null(IrAnalyze *ira, IrInstruction *source_inst, IrInstruction *value) {18187static IrInstruction *ir_analyze_test_non_null(IrAnalyze *ira, IrInstruction *source_inst, IrInstruction *value) {
...@@ -24697,18 +24765,22 @@ static IrInstruction *ir_analyze_instruction_suspend_finish(IrAnalyze *ira,...@@ -24697,18 +24765,22 @@ static IrInstruction *ir_analyze_instruction_suspend_finish(IrAnalyze *ira,
24697}24765}
2469824766
24699static IrInstruction *analyze_frame_ptr_to_anyframe_T(IrAnalyze *ira, IrInstruction *source_instr,24767static IrInstruction *analyze_frame_ptr_to_anyframe_T(IrAnalyze *ira, IrInstruction *source_instr,
24700 IrInstruction *frame_ptr)24768 IrInstruction *frame_ptr, ZigFn **target_fn)
24701{24769{
24702 if (type_is_invalid(frame_ptr->value.type))24770 if (type_is_invalid(frame_ptr->value.type))
24703 return ira->codegen->invalid_instruction;24771 return ira->codegen->invalid_instruction;
2470424772
24773 *target_fn = nullptr;
24774
24705 ZigType *result_type;24775 ZigType *result_type;
24706 IrInstruction *frame;24776 IrInstruction *frame;
24707 if (frame_ptr->value.type->id == ZigTypeIdPointer &&24777 if (frame_ptr->value.type->id == ZigTypeIdPointer &&
24708 frame_ptr->value.type->data.pointer.ptr_len == PtrLenSingle &&24778 frame_ptr->value.type->data.pointer.ptr_len == PtrLenSingle &&
24709 frame_ptr->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame)24779 frame_ptr->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame)
24710 {24780 {
24711 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;
24712 frame = frame_ptr;24784 frame = frame_ptr;
24713 } else {24785 } else {
24714 frame = ir_get_deref(ira, source_instr, frame_ptr, nullptr);24786 frame = ir_get_deref(ira, source_instr, frame_ptr, nullptr);
...@@ -24716,7 +24788,9 @@ static IrInstruction *analyze_frame_ptr_to_anyframe_T(IrAnalyze *ira, IrInstruct...@@ -24716,7 +24788,9 @@ static IrInstruction *analyze_frame_ptr_to_anyframe_T(IrAnalyze *ira, IrInstruct
24716 frame->value.type->data.pointer.ptr_len == PtrLenSingle &&24788 frame->value.type->data.pointer.ptr_len == PtrLenSingle &&
24717 frame->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame)24789 frame->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame)
24718 {24790 {
24719 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;
24720 } else if (frame->value.type->id != ZigTypeIdAnyFrame ||24794 } else if (frame->value.type->id != ZigTypeIdAnyFrame ||
24721 frame->value.type->data.any_frame.result_type == nullptr)24795 frame->value.type->data.any_frame.result_type == nullptr)
24722 {24796 {
...@@ -24737,7 +24811,11 @@ static IrInstruction *analyze_frame_ptr_to_anyframe_T(IrAnalyze *ira, IrInstruct...@@ -24737,7 +24811,11 @@ static IrInstruction *analyze_frame_ptr_to_anyframe_T(IrAnalyze *ira, IrInstruct
24737}24811}
2473824812
24739static IrInstruction *ir_analyze_instruction_await(IrAnalyze *ira, IrInstructionAwaitSrc *instruction) {24813static IrInstruction *ir_analyze_instruction_await(IrAnalyze *ira, IrInstructionAwaitSrc *instruction) {
24740 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);
24741 if (type_is_invalid(frame->value.type))24819 if (type_is_invalid(frame->value.type))
24742 return ira->codegen->invalid_instruction;24820 return ira->codegen->invalid_instruction;
2474324821
...@@ -24746,8 +24824,11 @@ static IrInstruction *ir_analyze_instruction_await(IrAnalyze *ira, IrInstruction...@@ -24746,8 +24824,11 @@ static IrInstruction *ir_analyze_instruction_await(IrAnalyze *ira, IrInstruction
24746 ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);24824 ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
24747 ir_assert(fn_entry != nullptr, &instruction->base);24825 ir_assert(fn_entry != nullptr, &instruction->base);
2474824826
24749 if (fn_entry->inferred_async_node == nullptr) {24827 // If it's not @Frame(func) then it's definitely a suspend point
24750 fn_entry->inferred_async_node = instruction->base.source_node;24828 if (target_fn == nullptr) {
24829 if (fn_entry->inferred_async_node == nullptr) {
24830 fn_entry->inferred_async_node = instruction->base.source_node;
24831 }
24751 }24832 }
2475224833
24753 if (type_can_fail(result_type)) {24834 if (type_can_fail(result_type)) {
...@@ -24764,8 +24845,10 @@ static IrInstruction *ir_analyze_instruction_await(IrAnalyze *ira, IrInstruction...@@ -24764,8 +24845,10 @@ static IrInstruction *ir_analyze_instruction_await(IrAnalyze *ira, IrInstruction
24764 result_loc = nullptr;24845 result_loc = nullptr;
24765 }24846 }
2476624847
24767 IrInstruction *result = ir_build_await_gen(ira, &instruction->base, frame, result_type, result_loc);24848 IrInstructionAwaitGen *result = ir_build_await_gen(ira, &instruction->base, frame, result_type, result_loc);
24768 return ir_finish_anal(ira, result);24849 result->target_fn = target_fn;
24850 fn_entry->await_list.append(result);
24851 return ir_finish_anal(ira, &result->base);
24769}24852}
2477024853
24771static IrInstruction *ir_analyze_instruction_resume(IrAnalyze *ira, IrInstructionResume *instruction) {24854static IrInstruction *ir_analyze_instruction_resume(IrAnalyze *ira, IrInstructionResume *instruction) {
...@@ -25548,6 +25631,61 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {...@@ -25548,6 +25631,61 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {
25548 bigint_init_unsigned(&val->data.x_bigint, align_in_bytes);25631 bigint_init_unsigned(&val->data.x_bigint, align_in_bytes);
25549 return ErrorNone;25632 return ErrorNone;
25550 }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 }
25551 case LazyValueIdSliceType: {25689 case LazyValueIdSliceType: {
25552 LazyValueSliceType *lazy_slice_type = reinterpret_cast<LazyValueSliceType *>(val->data.x_lazy);25690 LazyValueSliceType *lazy_slice_type = reinterpret_cast<LazyValueSliceType *>(val->data.x_lazy);
25553 IrAnalyze *ira = lazy_slice_type->ira;25691 IrAnalyze *ira = lazy_slice_type->ira;
src/userland.h+2
...@@ -75,6 +75,8 @@ enum Error {...@@ -75,6 +75,8 @@ enum Error {
75 ErrorOperationAborted,75 ErrorOperationAborted,
76 ErrorBrokenPipe,76 ErrorBrokenPipe,
77 ErrorNoSpaceLeft,77 ErrorNoSpaceLeft,
78 ErrorNotLazy,
79 ErrorIsAsync,
78};80};
7981
80// ABI warning82// ABI warning
std/mem.zig+6-5
...@@ -75,15 +75,16 @@ pub const Allocator = struct {...@@ -75,15 +75,16 @@ pub const Allocator = struct {
75 new_alignment: u29,75 new_alignment: u29,
76 ) []u8,76 ) []u8,
7777
78 /// Call `destroy` with the result.78 /// Returns a pointer to undefined memory.
79 /// Returns undefined memory.79 /// Call `destroy` with the result to free the memory.
80 pub fn create(self: *Allocator, comptime T: type) Error!*T {80 pub fn create(self: *Allocator, comptime T: type) Error!*T {
81 if (@sizeOf(T) == 0) return &(T{});81 if (@sizeOf(T) == 0) return &(T{});
82 const slice = try self.alloc(T, 1);82 const slice = try self.alloc(T, 1);
83 return &slice[0];83 return &slice[0];
84 }84 }
8585
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 pub fn destroy(self: *Allocator, ptr: var) void {88 pub fn destroy(self: *Allocator, ptr: var) void {
88 const T = @typeOf(ptr).Child;89 const T = @typeOf(ptr).Child;
89 if (@sizeOf(T) == 0) return;90 if (@sizeOf(T) == 0) return;
...@@ -92,7 +93,7 @@ pub const Allocator = struct {...@@ -92,7 +93,7 @@ pub const Allocator = struct {
92 assert(shrink_result.len == 0);93 assert(shrink_result.len == 0);
93 }94 }
9495
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 return self.alignedAlloc(T, @alignOf(T), n);97 return self.alignedAlloc(T, @alignOf(T), n);
97 }98 }
9899
...@@ -101,7 +102,7 @@ pub const Allocator = struct {...@@ -101,7 +102,7 @@ pub const Allocator = struct {
101 comptime T: type,102 comptime T: type,
102 comptime alignment: u29,103 comptime alignment: u29,
103 n: usize,104 n: usize,
104 ) ![]align(alignment) T {105 ) Error![]align(alignment) T {
105 if (n == 0) {106 if (n == 0) {
106 return ([*]align(alignment) T)(undefined)[0..0];107 return ([*]align(alignment) T)(undefined)[0..0];
107 }108 }
test/compile_errors.zig+4-4
...@@ -273,7 +273,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -273,7 +273,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
273 \\}273 \\}
274 ,274 ,
275 "tmp.zig:1:1: error: function with calling convention 'ccc' cannot be async",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 );
278278
279 cases.add(279 cases.add(
...@@ -507,11 +507,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -507,11 +507,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
507507
508 cases.add(508 cases.add(
509 "@sizeOf bad type",509 "@sizeOf bad type",
510 \\export fn entry() void {510 \\export fn entry() usize {
511 \\ _ = @sizeOf(@typeOf(null));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 );
516516
517 cases.add(517 cases.add(
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,3 +844,13 @@ test "cast fn to async fn when it is inferred to be async" {
844 resume S.frame;844 resume S.frame;
845 expect(S.ok);845 expect(S.ok);
846}846}
847
848test "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/sizeof_and_typeof.zig+15
...@@ -74,3 +74,18 @@ test "@sizeOf on compile-time types" {...@@ -74,3 +74,18 @@ test "@sizeOf on compile-time types" {
74 expect(@sizeOf(@typeOf(.hi)) == 0);74 expect(@sizeOf(@typeOf(.hi)) == 0);
75 expect(@sizeOf(@typeOf(type)) == 0);75 expect(@sizeOf(@typeOf(type)) == 0);
76}76}
77
78test "@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}