diff --git a/BRANCH_TODO b/BRANCH_TODO index 854b2c0ee..fba18ed35 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,6 +1,9 @@ Scratch pad for stuff to do before merging master ================================================= +struct & array init when the result is casted to anyerror!T +struct & array init when the result is casted to anyerror!?T + uncomment all the behavior tests look at all the ir_gen_node ir_gen_node_extra calls and make sure result locations are properly propagated diff --git a/src/all_types.hpp b/src/all_types.hpp index 1d935fee2..35f8745fd 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2770,8 +2770,9 @@ struct IrInstructionTestNonNull { struct IrInstructionOptionalUnwrapPtr { IrInstruction base; - IrInstruction *base_ptr; bool safety_check_on; + bool initializing; + IrInstruction *base_ptr; }; struct IrInstructionCtz { diff --git a/src/codegen.cpp b/src/codegen.cpp index 7ee299aab..2d1ea07bf 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -838,9 +838,7 @@ static LLVMValueRef gen_store_untyped(CodeGen *g, LLVMValueRef value, LLVMValueR { LLVMValueRef instruction = LLVMBuildStore(g->builder, value, ptr); if (is_volatile) LLVMSetVolatile(instruction, true); - if (alignment == 0) { - LLVMSetAlignment(instruction, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(value))); - } else { + if (alignment != 0) { LLVMSetAlignment(instruction, alignment); } return instruction; @@ -2384,16 +2382,19 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut } static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) { + if (return_instruction->value == nullptr) { + LLVMBuildRetVoid(g->builder); + return nullptr; + } + ZigType *return_type = return_instruction->value->value.type; if (want_first_arg_sret(g, &g->cur_fn->type_entry->data.fn.fn_type_id)) { assert(g->cur_ret_ptr); - if (return_instruction->value->value.special != ConstValSpecialRuntime) { - // if it's comptime we have to do this but if it's runtime trust that - // result location mechanism took care of it. - LLVMValueRef value = ir_llvm_value(g, return_instruction->value); - gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value); - } + src_assert(return_instruction->value->value.special != ConstValSpecialRuntime, + return_instruction->base.source_node); + LLVMValueRef value = ir_llvm_value(g, return_instruction->value); + gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value); LLVMBuildRetVoid(g->builder); } else if (handle_is_ptr(return_type)) { LLVMValueRef value = ir_llvm_value(g, return_instruction->value); @@ -4068,9 +4069,9 @@ static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *exec ZigType *maybe_type = ptr_type->data.pointer.child_type; assert(maybe_type->id == ZigTypeIdOptional); ZigType *child_type = maybe_type->data.maybe.child_type; - LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->base_ptr); - if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on) { - LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type); + LLVMValueRef base_ptr = ir_llvm_value(g, instruction->base_ptr); + if (instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base)) { + LLVMValueRef maybe_handle = get_handle_value(g, base_ptr, maybe_type, ptr_type); LLVMValueRef non_null_bit = gen_non_null_bit(g, maybe_type, maybe_handle); LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalFail"); LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalOk"); @@ -4086,10 +4087,16 @@ static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *exec } else { bool is_scalar = !handle_is_ptr(maybe_type); if (is_scalar) { - return maybe_ptr; + return base_ptr; } else { - LLVMValueRef maybe_struct_ref = get_handle_value(g, maybe_ptr, maybe_type, ptr_type); - return LLVMBuildStructGEP(g->builder, maybe_struct_ref, maybe_child_index, ""); + LLVMValueRef optional_struct_ref = get_handle_value(g, base_ptr, maybe_type, ptr_type); + if (instruction->initializing) { + LLVMValueRef non_null_bit_ptr = LLVMBuildStructGEP(g->builder, optional_struct_ref, + maybe_null_index, ""); + LLVMValueRef non_null_bit = LLVMConstInt(LLVMInt1Type(), 1, false); + gen_store_untyped(g, non_null_bit, non_null_bit_ptr, 0, false); + } + return LLVMBuildStructGEP(g->builder, optional_struct_ref, maybe_child_index, ""); } } } diff --git a/src/ir.cpp b/src/ir.cpp index b05fe835b..31c40ac16 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -187,6 +187,8 @@ static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_ ZigType *dest_type); static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_source_instr, ResultLoc *result_loc, ZigType *value_type, IrInstruction *value); +static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *base_ptr, bool safety_check_on, bool initializing); static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { assert(get_src_ptr_type(const_val->type) != nullptr); @@ -1095,13 +1097,15 @@ static IrInstruction *ir_build_cond_br(IrBuilder *irb, Scope *scope, AstNode *so return &cond_br_instruction->base; } -static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *return_value) { +static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *return_value) +{ IrInstructionReturn *return_instruction = ir_build_instruction(irb, scope, source_node); return_instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable; return_instruction->base.value.special = ConstValSpecialStatic; return_instruction->value = return_value; - ir_ref_instruction(return_value, irb->current_basic_block); + if (return_value != nullptr) ir_ref_instruction(return_value, irb->current_basic_block); return &return_instruction->base; } @@ -1756,11 +1760,12 @@ static IrInstruction *ir_build_test_nonnull(IrBuilder *irb, Scope *scope, AstNod } static IrInstruction *ir_build_optional_unwrap_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *base_ptr, bool safety_check_on) + IrInstruction *base_ptr, bool safety_check_on, bool initializing) { IrInstructionOptionalUnwrapPtr *instruction = ir_build_instruction(irb, scope, source_node); instruction->base_ptr = base_ptr; instruction->safety_check_on = safety_check_on; + instruction->initializing = initializing; ir_ref_instruction(base_ptr, irb->current_basic_block); @@ -3918,7 +3923,7 @@ static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode ir_mark_gen(ir_build_br(irb, parent_scope, node, end_block, is_comptime)); ir_set_cursor_at_end_and_append_block(irb, ok_block); - IrInstruction *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, parent_scope, node, maybe_ptr, false); + IrInstruction *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, parent_scope, node, maybe_ptr, false, false); IrInstruction *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr); ir_build_end_expr(irb, parent_scope, node, unwrapped_payload, &peer_parent->peers[1].base); IrBasicBlock *after_ok_block = irb->current_basic_block; @@ -6009,7 +6014,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n ResultLocPeerParent *peer_parent = create_binary_result_peers(cond_br_inst, else_block, end_block, result_loc); ir_set_cursor_at_end_and_append_block(irb, body_block); - IrInstruction *payload_ptr = ir_build_optional_unwrap_ptr(irb, child_scope, symbol_node, maybe_val_ptr, false); + IrInstruction *payload_ptr = ir_build_optional_unwrap_ptr(irb, child_scope, symbol_node, maybe_val_ptr, false, false); IrInstruction *var_ptr = node->data.while_expr.var_is_ptr ? ir_build_ref(irb, child_scope, symbol_node, payload_ptr, true, false) : payload_ptr; ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, var_ptr); @@ -6609,7 +6614,7 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN ZigVar *var = ir_create_var(irb, node, subexpr_scope, var_symbol, is_const, is_const, is_shadowable, is_comptime); - IrInstruction *payload_ptr = ir_build_optional_unwrap_ptr(irb, subexpr_scope, node, maybe_val_ptr, false); + IrInstruction *payload_ptr = ir_build_optional_unwrap_ptr(irb, subexpr_scope, node, maybe_val_ptr, false, false); IrInstruction *var_ptr = var_is_ptr ? ir_build_ref(irb, subexpr_scope, node, payload_ptr, true, false) : payload_ptr; ir_build_var_decl_src(irb, subexpr_scope, node, var, nullptr, var_ptr); var_scope = var->child_scope; @@ -8094,7 +8099,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop if (maybe_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; - IrInstruction *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, scope, node, maybe_ptr, true); + IrInstruction *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, scope, node, maybe_ptr, true, false); if (lval == LValPtr) return unwrapped_ptr; @@ -8375,7 +8380,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec // a register or local variable which does not get spilled into the frame, // otherwise llvm tries to access memory inside the destroyed frame. IrInstruction *unwrapped_await_handle_ptr = ir_build_optional_unwrap_ptr(irb, scope, node, - irb->exec->await_handle_var_ptr, false); + irb->exec->await_handle_var_ptr, false, false); IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr); ir_build_br(irb, scope, node, check_free_block, const_bool_false); @@ -12871,6 +12876,14 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio if (type_is_invalid(value->value.type)) return ir_unreach_error(ira); + if (!instr_is_comptime(value) && handle_is_ptr(ira->explicit_return_type)) { + // result location mechanism took care of it. + IrInstruction *result = ir_build_return(&ira->new_irb, instruction->base.scope, + instruction->base.source_node, nullptr); + result->value.type = ira->codegen->builtin_types.entry_unreachable; + return ir_finish_anal(ira, result); + } + IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->explicit_return_type); if (type_is_invalid(casted_value->value.type)) { AstNode *source_node = ira->explicit_return_type_source_node; @@ -14925,10 +14938,17 @@ static IrInstruction *ir_analyze_instruction_implicit_cast(IrAnalyze *ira, IrIns } static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, IrInstructionResolveResult *instruction) { - ZigType *ty = ir_resolve_type(ira, instruction->ty->child); - if (type_is_invalid(ty)) + ZigType *implicit_elem_type = ir_resolve_type(ira, instruction->ty->child); + if (type_is_invalid(implicit_elem_type)) return ira->codegen->invalid_instruction; - return ir_resolve_result(ira, &instruction->base, instruction->result_loc, ty, nullptr); + IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, + implicit_elem_type, nullptr); + ir_assert(result_loc->value.type->id == ZigTypeIdPointer, &instruction->base); + ZigType *actual_elem_type = result_loc->value.type->data.pointer.child_type; + if (actual_elem_type->id == ZigTypeIdOptional && implicit_elem_type->id != ZigTypeIdOptional) { + return ir_analyze_unwrap_optional_payload(ira, &instruction->base, result_loc, false, true); + } + return result_loc; } static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry, @@ -17876,7 +17896,7 @@ static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIns } static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstruction *source_instr, - IrInstruction *base_ptr, bool safety_check_on) + IrInstruction *base_ptr, bool safety_check_on, bool initializing) { ZigType *ptr_type = base_ptr->value.type; assert(ptr_type->id == ZigTypeIdPointer); @@ -17948,7 +17968,7 @@ static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstr } IrInstruction *result = ir_build_optional_unwrap_ptr(&ira->new_irb, source_instr->scope, - source_instr->source_node, base_ptr, safety_check_on); + source_instr->source_node, base_ptr, safety_check_on, initializing); result->value.type = result_type; return result; } @@ -17960,7 +17980,8 @@ static IrInstruction *ir_analyze_instruction_optional_unwrap_ptr(IrAnalyze *ira, if (type_is_invalid(base_ptr->value.type)) return ira->codegen->invalid_instruction; - return ir_analyze_unwrap_optional_payload(ira, &instruction->base, base_ptr, instruction->safety_check_on); + return ir_analyze_unwrap_optional_payload(ira, &instruction->base, base_ptr, + instruction->safety_check_on, false); } static IrInstruction *ir_analyze_instruction_ctz(IrAnalyze *ira, IrInstructionCtz *instruction) { diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 1935c0d7f..64e6f07ad 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -61,9 +61,10 @@ static void ir_print_other_block(IrPrint *irp, IrBasicBlock *bb) { } static void ir_print_return(IrPrint *irp, IrInstructionReturn *return_instruction) { - assert(return_instruction->value); fprintf(irp->f, "return "); - ir_print_other_instruction(irp, return_instruction->value); + if (return_instruction->value != nullptr) { + ir_print_other_instruction(irp, return_instruction->value); + } } static void ir_print_const(IrPrint *irp, IrInstructionConst *const_instruction) {