From d291d3c8c00450e31b7cce15eae43db265361186 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 2 Sep 2019 13:07:44 -0400 Subject: fix using @typeOf on a generic function call --- src/ir.cpp | 58 +++++++++++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 25 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index e1c7bb37fe..3727e87915 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -15648,6 +15648,31 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source return &store_ptr->base; } +static IrInstruction *analyze_casted_new_stack(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, + ZigFn *fn_entry) +{ + if (call_instruction->new_stack == nullptr) + return nullptr; + + IrInstruction *new_stack = call_instruction->new_stack->child; + if (type_is_invalid(new_stack->value.type)) + return ira->codegen->invalid_instruction; + + if (call_instruction->is_async_call_builtin && + fn_entry != nullptr && new_stack->value.type->id == ZigTypeIdPointer && + new_stack->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame) + { + ZigType *needed_frame_type = get_pointer_to_type(ira->codegen, + get_fn_frame_type(ira->codegen, fn_entry), false); + return ir_implicit_cast(ira, new_stack, needed_frame_type); + } else { + ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, + false, false, PtrLenUnknown, target_fn_align(ira->codegen->zig_target), 0, 0, false); + ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr); + return ir_implicit_cast(ira, new_stack, u8_slice); + } +} + static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref, IrInstruction *first_arg_ptr, bool comptime_fn_call, FnInline fn_inline) @@ -15826,31 +15851,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c return ir_finish_anal(ira, new_instruction); } - IrInstruction *casted_new_stack = nullptr; - if (call_instruction->new_stack != nullptr) { - IrInstruction *new_stack = call_instruction->new_stack->child; - if (type_is_invalid(new_stack->value.type)) - return ira->codegen->invalid_instruction; - - if (call_instruction->is_async_call_builtin && - fn_entry != nullptr && new_stack->value.type->id == ZigTypeIdPointer && - new_stack->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame) - { - ZigType *needed_frame_type = get_pointer_to_type(ira->codegen, - get_fn_frame_type(ira->codegen, fn_entry), false); - casted_new_stack = ir_implicit_cast(ira, new_stack, needed_frame_type); - if (type_is_invalid(casted_new_stack->value.type)) - return ira->codegen->invalid_instruction; - } else { - ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, - false, false, PtrLenUnknown, target_fn_align(ira->codegen->zig_target), 0, 0, false); - ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr); - casted_new_stack = ir_implicit_cast(ira, new_stack, u8_slice); - if (type_is_invalid(casted_new_stack->value.type)) - return ira->codegen->invalid_instruction; - } - } - if (fn_type->data.fn.is_generic) { if (!fn_entry) { ir_add_error(ira, call_instruction->fn_ref, @@ -16063,6 +16063,10 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c parent_fn_entry->calls_or_awaits_errorable_fn = true; } + IrInstruction *casted_new_stack = analyze_casted_new_stack(ira, call_instruction, impl_fn); + if (casted_new_stack != nullptr && type_is_invalid(casted_new_stack->value.type)) + return ira->codegen->invalid_instruction; + size_t impl_param_count = impl_fn_type_id->param_count; if (call_instruction->is_async) { IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry, @@ -16211,6 +16215,10 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c return ira->codegen->invalid_instruction; } + IrInstruction *casted_new_stack = analyze_casted_new_stack(ira, call_instruction, fn_entry); + if (casted_new_stack != nullptr && type_is_invalid(casted_new_stack->value.type)) + return ira->codegen->invalid_instruction; + if (call_instruction->is_async) { IrInstruction *result = ir_analyze_async_call(ira, call_instruction, fn_entry, fn_type, fn_ref, casted_args, call_param_count, casted_new_stack); -- cgit v1.2.3 From ab4cba14c8aac7151b4c10094fea4211694da145 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 2 Sep 2019 14:35:41 -0400 Subject: fix recursive call of await @asyncCall with struct return type --- src/ir.cpp | 22 ++++++++++++---------- test/stage1/behavior/async_fn.zig | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 10 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 3727e87915..01066e51c3 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -330,6 +330,8 @@ static bool ir_should_inline(IrExecutable *exec, Scope *scope) { while (scope != nullptr) { if (scope->id == ScopeIdCompTime) return true; + if (scope->id == ScopeIdTypeOf) + return false; if (scope->id == ScopeIdFnDef) break; scope = scope->parent; @@ -16075,11 +16077,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c } IrInstruction *result_loc; - if (call_instruction->is_async_call_builtin) { - result_loc = get_async_call_result_loc(ira, call_instruction, impl_fn_type_id->return_type); - if (result_loc != nullptr && type_is_invalid(result_loc->value.type)) - return ira->codegen->invalid_instruction; - } else if (handle_is_ptr(impl_fn_type_id->return_type)) { + if (handle_is_ptr(impl_fn_type_id->return_type)) { result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, impl_fn_type_id->return_type, nullptr, true, true, false); if (result_loc != nullptr) { @@ -16091,6 +16089,10 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c result_loc = nullptr; } } + } else if (call_instruction->is_async_call_builtin) { + result_loc = get_async_call_result_loc(ira, call_instruction, impl_fn_type_id->return_type); + if (result_loc != nullptr && type_is_invalid(result_loc->value.type)) + return ira->codegen->invalid_instruction; } else { result_loc = nullptr; } @@ -16231,11 +16233,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c } IrInstruction *result_loc; - if (call_instruction->is_async_call_builtin) { - result_loc = get_async_call_result_loc(ira, call_instruction, return_type); - if (result_loc != nullptr && type_is_invalid(result_loc->value.type)) - return ira->codegen->invalid_instruction; - } else if (handle_is_ptr(return_type)) { + if (handle_is_ptr(return_type)) { result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, return_type, nullptr, true, true, false); if (result_loc != nullptr) { @@ -16247,6 +16245,10 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c result_loc = nullptr; } } + } else if (call_instruction->is_async_call_builtin) { + result_loc = get_async_call_result_loc(ira, call_instruction, return_type); + if (result_loc != nullptr && type_is_invalid(result_loc->value.type)) + return ira->codegen->invalid_instruction; } else { result_loc = nullptr; } diff --git a/test/stage1/behavior/async_fn.zig b/test/stage1/behavior/async_fn.zig index 605a725e4b..ad8e949f8b 100644 --- a/test/stage1/behavior/async_fn.zig +++ b/test/stage1/behavior/async_fn.zig @@ -1056,3 +1056,39 @@ test "using @typeOf on a generic function call" { resume S.global_frame; expect(S.global_ok); } + +test "recursive call of await @asyncCall with struct return type" { + const S = struct { + var global_frame: anyframe = undefined; + var global_ok = false; + + var buf: [100]u8 align(16) = undefined; + + fn amain(x: var) Foo { + if (x == 0) { + global_ok = true; + return Foo{ .x = 1, .y = 2, .z = 3 }; + } + suspend { + global_frame = @frame(); + } + const F = @typeOf(async amain(x - 1)); + const frame = @intToPtr(*F, @ptrToInt(&buf)); + return await @asyncCall(frame, {}, amain, x - 1); + } + + const Foo = struct { + x: u64, + y: u64, + z: u64, + }; + }; + var res: S.Foo = undefined; + var frame: @typeOf(async S.amain(u32(1))) = undefined; + _ = @asyncCall(&frame, &res, S.amain, u32(1)); + resume S.global_frame; + expect(S.global_ok); + expect(res.x == 1); + expect(res.y == 2); + expect(res.z == 3); +} -- cgit v1.2.3 From d74b8567cf6a81550831a9ea02f2cebcb4db9846 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 2 Sep 2019 21:22:35 -0400 Subject: omit prefix data for async functions sometimes When `@frameSize` is never called, and `@asyncCall` on a runtime-known pointer is never used, no prefix data for async functions is needed. Related: #3160 --- src/all_types.hpp | 1 + src/codegen.cpp | 5 ++++- src/ir.cpp | 3 +++ 3 files changed, 8 insertions(+), 1 deletion(-) (limited to 'src/ir.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 708db8848d..1a97cf2814 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1989,6 +1989,7 @@ struct CodeGen { bool system_linker_hack; bool reported_bad_link_libc_error; bool is_dynamic; // shared library rather than static library. dynamic musl rather than static musl. + bool need_frame_size_prefix_data; //////////////////////////// Participates in Input Parameter Cache Hash /////// Note: there is a separate cache hash for builtin.zig, when adding fields, diff --git a/src/codegen.cpp b/src/codegen.cpp index 0b51df1e82..b694923873 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3775,6 +3775,7 @@ static void render_async_var_decls(CodeGen *g, Scope *scope) { } static LLVMValueRef gen_frame_size(CodeGen *g, LLVMValueRef fn_val) { + assert(g->need_frame_size_prefix_data); LLVMTypeRef usize_llvm_type = g->builtin_types.entry_usize->llvm_type; LLVMTypeRef ptr_usize_llvm_type = LLVMPointerType(usize_llvm_type, 0); LLVMValueRef casted_fn_val = LLVMBuildBitCast(g->builder, fn_val, ptr_usize_llvm_type, ""); @@ -7208,7 +7209,9 @@ static void do_code_gen(CodeGen *g) { LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; LLVMValueRef size_val = LLVMConstInt(usize_type_ref, fn_table_entry->frame_type->abi_size, false); - ZigLLVMFunctionSetPrefixData(fn_table_entry->llvm_value, size_val); + if (g->need_frame_size_prefix_data) { + ZigLLVMFunctionSetPrefixData(fn_table_entry->llvm_value, size_val); + } if (!g->strip_debug_symbols) { AstNode *source_node = fn_table_entry->proto_node; diff --git a/src/ir.cpp b/src/ir.cpp index 01066e51c3..e3b440d0f5 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -15671,6 +15671,7 @@ static IrInstruction *analyze_casted_new_stack(IrAnalyze *ira, IrInstructionCall ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, false, false, PtrLenUnknown, target_fn_align(ira->codegen->zig_target), 0, 0, false); ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr); + ira->codegen->need_frame_size_prefix_data = true; return ir_implicit_cast(ira, new_stack, u8_slice); } } @@ -22533,6 +22534,8 @@ static IrInstruction *ir_analyze_instruction_frame_size(IrAnalyze *ira, IrInstru return ira->codegen->invalid_instruction; } + ira->codegen->need_frame_size_prefix_data = true; + IrInstruction *result = ir_build_frame_size_gen(&ira->new_irb, instruction->base.scope, instruction->base.source_node, fn); result->value.type = ira->codegen->builtin_types.entry_usize; -- cgit v1.2.3 From 18620756520d198f581b9a9acbf25c8cbb79ad11 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 3 Sep 2019 18:25:00 -0400 Subject: fix union field ptr ir instruction --- src/ir.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index e3b440d0f5..abf4f477a8 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -17464,7 +17464,12 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ return ir_analyze_container_member_access_inner(ira, bare_type, field_name, source_instr, container_ptr, container_type); } - ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field->type_entry, + + ZigType *field_type = resolve_union_field_type(ira->codegen, field); + if (field_type == nullptr) + return ira->codegen->invalid_instruction; + + ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field_type, is_const, is_volatile, PtrLenSingle, 0, 0, 0, false); if (instr_is_comptime(container_ptr)) { ConstExprValue *ptr_val = ir_resolve_const(ira, container_ptr, UndefBad); @@ -17481,7 +17486,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ if (initializing) { ConstExprValue *payload_val = create_const_vals(1); payload_val->special = ConstValSpecialUndef; - payload_val->type = field->type_entry; + payload_val->type = field_type; payload_val->parent.id = ConstParentIdUnion; payload_val->parent.data.p_union.union_val = union_val; -- cgit v1.2.3 From ce14c543d165efbd926ea6bd654d999c625b366f Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Tue, 3 Sep 2019 22:29:04 +0200 Subject: error message and test for alignment of variables of zero-bit types --- src/analyze.cpp | 4 ++++ src/ir.cpp | 6 ++++++ test/compile_errors.zig | 9 +++++++++ 3 files changed, 19 insertions(+) (limited to 'src/ir.cpp') diff --git a/src/analyze.cpp b/src/analyze.cpp index 188da18515..2fd540a64f 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2671,6 +2671,10 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { } } + if (!type_has_bits(struct_type)) { + assert(struct_type->abi_align == 0); + } + struct_type->data.structure.resolve_loop_flag_other = false; if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) { diff --git a/src/ir.cpp b/src/ir.cpp index abf4f477a8..7415a2dd6b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -14839,6 +14839,12 @@ static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_in if (align != 0) { if ((err = type_resolve(ira->codegen, var_type, ResolveStatusAlignmentKnown))) return ira->codegen->invalid_instruction; + if (!type_has_bits(var_type)) { + ir_add_error(ira, source_inst, + buf_sprintf("variable '%s' of zero-bit type '%s' has no in-memory representation, it cannot be aligned", + name_hint, buf_ptr(&var_type->name))); + return ira->codegen->invalid_instruction; + } } assert(result->base.value.data.x_ptr.special != ConstPtrSpecialInvalid); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 12f17ec790..871ff63e23 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -6462,4 +6462,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:5:30: error: expression value is ignored", "tmp.zig:9:30: error: expression value is ignored", ); + + cases.add( + "aligned variable of zero-bit type", + \\export fn f() void { + \\ var s: struct {} align(4) = undefined; + \\} + , + "tmp.zig:2:5: error: variable 's' of zero-bit type 'struct:2:12' has no in-memory representation, it cannot be aligned", + ); } -- cgit v1.2.3