authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-05-25 13:48:10-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-05-25 13:48:10-04:00
logfcdd808c5c1b866c2582a17839a53ce7bbbb78d6
tree5c8d30ee489a33022ff28d5916d437dd02b5c960
parent68add5d8286e5c517143b16a457a86a6c23dbc64

fix segfault with array of variadic functions

closes #377

5 files changed, 52 insertions(+), 6 deletions(-)

src/all_types.hpp+1
......@@ -2399,6 +2399,7 @@ struct IrInstructionFnProto {
23992399
24002400 IrInstruction **param_types;
24012401 IrInstruction *return_type;
2402 bool is_var_args;
24022403};
24032404
24042405// true if the target value is compile time known, false otherwise
src/analyze.cpp+11-2
......@@ -987,7 +987,7 @@ TypeTableEntry *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) {
987987 return result->value.data.x_type;
988988}
989989
990static TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
990TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
991991 TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
992992 fn_type->is_copyable = false;
993993 buf_init_from_str(&fn_type->name, "fn(");
......@@ -2504,7 +2504,11 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *
25042504 if (expected_type->data.fn.fn_type_id.is_cold != actual_type->data.fn.fn_type_id.is_cold) {
25052505 return false;
25062506 }
2507 if (actual_type->data.fn.fn_type_id.return_type->id != TypeTableEntryIdUnreachable &&
2507 if (expected_type->data.fn.fn_type_id.is_var_args != actual_type->data.fn.fn_type_id.is_var_args) {
2508 return false;
2509 }
2510 if (!expected_type->data.fn.fn_type_id.is_var_args &&
2511 actual_type->data.fn.fn_type_id.return_type->id != TypeTableEntryIdUnreachable &&
25082512 !types_match_const_cast_only(
25092513 expected_type->data.fn.fn_type_id.return_type,
25102514 actual_type->data.fn.fn_type_id.return_type))
......@@ -2515,6 +2519,11 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *
25152519 return false;
25162520 }
25172521 for (size_t i = 0; i < expected_type->data.fn.fn_type_id.param_count; i += 1) {
2522 if (i == expected_type->data.fn.fn_type_id.param_count - 1 &&
2523 expected_type->data.fn.fn_type_id.is_var_args)
2524 {
2525 continue;
2526 }
25182527 // note it's reversed for parameters
25192528 FnTypeParamInfo *actual_param_info = &actual_type->data.fn.fn_type_id.param_info[i];
25202529 FnTypeParamInfo *expected_param_info = &expected_type->data.fn.fn_type_id.param_info[i];
src/analyze.hpp+1
......@@ -164,5 +164,6 @@ const char *type_id_name(TypeTableEntryId id);
164164TypeTableEntryId type_id_at_index(size_t index);
165165size_t type_id_len();
166166size_t type_id_index(TypeTableEntryId id);
167TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id);
167168
168169#endif
src/ir.cpp+27-4
......@@ -1857,14 +1857,17 @@ static IrInstruction *ir_build_unwrap_err_payload_from(IrBuilder *irb, IrInstruc
18571857}
18581858
18591859static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *source_node,
1860 IrInstruction **param_types, IrInstruction *return_type)
1860 IrInstruction **param_types, IrInstruction *return_type, bool is_var_args)
18611861{
18621862 IrInstructionFnProto *instruction = ir_build_instruction<IrInstructionFnProto>(irb, scope, source_node);
18631863 instruction->param_types = param_types;
18641864 instruction->return_type = return_type;
1865 instruction->is_var_args = is_var_args;
18651866
18661867 assert(source_node->type == NodeTypeFnProto);
1867 for (size_t i = 0; i < source_node->data.fn_proto.params.length; i += 1) {
1868 size_t param_count = source_node->data.fn_proto.params.length;
1869 if (is_var_args) param_count -= 1;
1870 for (size_t i = 0; i < param_count; i += 1) {
18681871 ir_ref_instruction(param_types[i], irb->current_basic_block);
18691872 }
18701873 ir_ref_instruction(return_type, irb->current_basic_block);
......@@ -5843,8 +5846,13 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
58435846 size_t param_count = node->data.fn_proto.params.length;
58445847 IrInstruction **param_types = allocate<IrInstruction*>(param_count);
58455848
5849 bool is_var_args = false;
58465850 for (size_t i = 0; i < param_count; i += 1) {
58475851 AstNode *param_node = node->data.fn_proto.params.at(i);
5852 if (param_node->data.param_decl.is_var_args) {
5853 is_var_args = true;
5854 break;
5855 }
58485856 AstNode *type_node = param_node->data.param_decl.type;
58495857 IrInstruction *type_value = ir_gen_node(irb, type_node, parent_scope);
58505858 if (type_value == irb->codegen->invalid_instruction)
......@@ -5856,7 +5864,7 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
58565864 if (return_type == irb->codegen->invalid_instruction)
58575865 return irb->codegen->invalid_instruction;
58585866
5859 return ir_build_fn_proto(irb, parent_scope, node, param_types, return_type);
5867 return ir_build_fn_proto(irb, parent_scope, node, param_types, return_type, is_var_args);
58605868}
58615869
58625870static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope,
......@@ -9039,7 +9047,11 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
90399047 }
90409048
90419049 if (fn_type->data.fn.is_generic) {
9042 assert(fn_entry);
9050 if (!fn_entry) {
9051 ir_add_error(ira, call_instruction->fn_ref,
9052 buf_sprintf("calling a generic function requires compile-time known function value"));
9053 return ira->codegen->builtin_types.entry_invalid;
9054 }
90439055
90449056 // Count the arguments of the function type id we are creating
90459057 size_t new_fn_arg_count = first_arg_1_or_0;
......@@ -13065,6 +13077,17 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc
1306513077 AstNode *param_node = proto_node->data.fn_proto.params.at(fn_type_id.next_param_index);
1306613078 assert(param_node->type == NodeTypeParamDecl);
1306713079
13080 bool param_is_var_args = param_node->data.param_decl.is_var_args;
13081 if (param_is_var_args) {
13082 if (fn_type_id.is_extern) {
13083 fn_type_id.param_count = fn_type_id.next_param_index;
13084 continue;
13085 } else {
13086 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
13087 out_val->data.x_type = get_generic_fn_type(ira->codegen, &fn_type_id);
13088 return ira->codegen->builtin_types.entry_type;
13089 }
13090 }
1306813091 IrInstruction *param_type_value = instruction->param_types[fn_type_id.next_param_index]->other;
1306913092
1307013093 FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index];
test/compile_errors.zig+12
......@@ -1892,4 +1892,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
18921892 \\}
18931893 ,
18941894 ".tmp_source.zig:3:9: error: cannot goto out of defer expression");
1895
1896 cases.add("calling a var args function only known at runtime",
1897 \\var foos = []fn(...) { foo1, foo2 };
1898 \\
1899 \\fn foo1(args: ...) {}
1900 \\fn foo2(args: ...) {}
1901 \\
1902 \\pub fn main() -> %void {
1903 \\ foos[0]();
1904 \\}
1905 ,
1906 ".tmp_source.zig:7:9: error: calling a generic function requires compile-time known function value");
18951907}