From 55b28ab0301237b8c9e39db4160036a42544f836 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 23 Apr 2016 12:21:47 -0700 Subject: [PATCH] fix returning empty struct from function closes #142 --- src/analyze.cpp | 7 +++---- src/codegen.cpp | 26 +++++++++++++++----------- test/self_hosted.zig | 15 +++++++++++++++ 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 572fa4df9c..b0efb7bbc1 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -623,7 +623,6 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { buf_appendf(&fn_type->name, " -> %s", buf_ptr(&fn_type_id->return_type->name)); } - // next, loop over the parameters again and compute debug information // and codegen information bool first_arg_return = handle_is_ptr(fn_type_id->return_type); @@ -634,15 +633,15 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { param_di_types[0] = fn_type_id->return_type->di_type; int gen_param_index = 0; TypeTableEntry *gen_return_type; - if (first_arg_return) { + if (!type_has_bits(fn_type_id->return_type)) { + gen_return_type = g->builtin_types.entry_void; + } else if (first_arg_return) { TypeTableEntry *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false); gen_param_types[gen_param_index] = gen_type->type_ref; gen_param_index += 1; // after the gen_param_index += 1 because 0 is the return type param_di_types[gen_param_index] = gen_type->di_type; gen_return_type = g->builtin_types.entry_void; - } else if (!type_has_bits(fn_type_id->return_type)) { - gen_return_type = g->builtin_types.entry_void; } else { gen_return_type = fn_type_id->return_type; } diff --git a/src/codegen.cpp b/src/codegen.cpp index 8ba76e0cfb..9422aeaa05 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -788,8 +788,10 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { TypeTableEntry *src_return_type = fn_type->data.fn.fn_type_id.return_type; + bool ret_has_bits = type_has_bits(src_return_type); + int fn_call_param_count = node->data.fn_call_expr.params.length; - bool first_arg_ret = handle_is_ptr(src_return_type); + bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type); int actual_param_count = fn_call_param_count + (struct_type ? 1 : 0) + (first_arg_ret ? 1 : 0); bool is_var_args = fn_type->data.fn.fn_type_id.is_var_args; @@ -824,10 +826,10 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { if (src_return_type->id == TypeTableEntryIdUnreachable) { return LLVMBuildUnreachable(g->builder); + } else if (!ret_has_bits) { + return nullptr; } else if (first_arg_ret) { return node->data.fn_call_expr.tmp_ptr; - } else if (!type_has_bits(src_return_type)) { - return nullptr; } else { return result; } @@ -1568,6 +1570,9 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType b LLVMValueRef target_ref, LLVMValueRef value, TypeTableEntry *op1_type, TypeTableEntry *op2_type) { + if (!type_has_bits(op1_type)) { + return nullptr; + } if (handle_is_ptr(op1_type)) { assert(op1_type == op2_type); assert(bin_op == BinOpTypeAssign); @@ -1584,7 +1589,8 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType b } add_debug_source_node(g, source_node); - return LLVMBuildStore(g->builder, value, target_ref); + LLVMBuildStore(g->builder, value, target_ref); + return nullptr; } static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) { @@ -1600,11 +1606,8 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) { LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2); - if (!type_has_bits(op1_type)) { - return nullptr; - } - - return gen_assign_raw(g, node, node->data.bin_op_expr.bin_op, target_ref, value, op1_type, op2_type); + gen_assign_raw(g, node, node->data.bin_op_expr.bin_op, target_ref, value, op1_type, op2_type); + return nullptr; } static LLVMValueRef gen_unwrap_maybe(CodeGen *g, AstNode *node, LLVMValueRef maybe_struct_ref) { @@ -1846,11 +1849,12 @@ static LLVMValueRef gen_return(CodeGen *g, AstNode *source_node, LLVMValueRef va assert(g->cur_ret_ptr); gen_assign_raw(g, source_node, BinOpTypeAssign, g->cur_ret_ptr, value, return_type, return_type); add_debug_source_node(g, source_node); - return LLVMBuildRetVoid(g->builder); + LLVMBuildRetVoid(g->builder); } else { add_debug_source_node(g, source_node); - return LLVMBuildRet(g->builder, value); + LLVMBuildRet(g->builder, value); } + return nullptr; } static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) { diff --git a/test/self_hosted.zig b/test/self_hosted.zig index 0673301092..29a04efba7 100644 --- a/test/self_hosted.zig +++ b/test/self_hosted.zig @@ -1299,3 +1299,18 @@ struct EmptyStruct { #attribute("test") fn @"weird function name"() { } + + +#attribute("test") +fn return_empty_struct_from_fn() { + test_return_empty_struct_from_fn(); + test_return_empty_struct_from_fn_noeval(); +} +struct EmptyStruct2 {} +fn test_return_empty_struct_from_fn() -> EmptyStruct2 { + EmptyStruct2 {} +} +#static_eval_enable(false) +fn test_return_empty_struct_from_fn_noeval() -> EmptyStruct2 { + EmptyStruct2 {} +}