fix segfault with array of variadic functions

closes #377
master
Andrew Kelley 2017-05-25 13:48:10 -04:00
parent 68add5d828
commit fcdd808c5c
5 changed files with 52 additions and 6 deletions

View File

@ -2399,6 +2399,7 @@ struct IrInstructionFnProto {
IrInstruction **param_types;
IrInstruction *return_type;
bool is_var_args;
};
// true if the target value is compile time known, false otherwise

View File

@ -987,7 +987,7 @@ TypeTableEntry *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) {
return result->value.data.x_type;
}
static TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
fn_type->is_copyable = false;
buf_init_from_str(&fn_type->name, "fn(");
@ -2504,7 +2504,11 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *
if (expected_type->data.fn.fn_type_id.is_cold != actual_type->data.fn.fn_type_id.is_cold) {
return false;
}
if (actual_type->data.fn.fn_type_id.return_type->id != TypeTableEntryIdUnreachable &&
if (expected_type->data.fn.fn_type_id.is_var_args != actual_type->data.fn.fn_type_id.is_var_args) {
return false;
}
if (!expected_type->data.fn.fn_type_id.is_var_args &&
actual_type->data.fn.fn_type_id.return_type->id != TypeTableEntryIdUnreachable &&
!types_match_const_cast_only(
expected_type->data.fn.fn_type_id.return_type,
actual_type->data.fn.fn_type_id.return_type))
@ -2515,6 +2519,11 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *
return false;
}
for (size_t i = 0; i < expected_type->data.fn.fn_type_id.param_count; i += 1) {
if (i == expected_type->data.fn.fn_type_id.param_count - 1 &&
expected_type->data.fn.fn_type_id.is_var_args)
{
continue;
}
// note it's reversed for parameters
FnTypeParamInfo *actual_param_info = &actual_type->data.fn.fn_type_id.param_info[i];
FnTypeParamInfo *expected_param_info = &expected_type->data.fn.fn_type_id.param_info[i];

View File

@ -164,5 +164,6 @@ const char *type_id_name(TypeTableEntryId id);
TypeTableEntryId type_id_at_index(size_t index);
size_t type_id_len();
size_t type_id_index(TypeTableEntryId id);
TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id);
#endif

View File

@ -1857,14 +1857,17 @@ static IrInstruction *ir_build_unwrap_err_payload_from(IrBuilder *irb, IrInstruc
}
static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction **param_types, IrInstruction *return_type)
IrInstruction **param_types, IrInstruction *return_type, bool is_var_args)
{
IrInstructionFnProto *instruction = ir_build_instruction<IrInstructionFnProto>(irb, scope, source_node);
instruction->param_types = param_types;
instruction->return_type = return_type;
instruction->is_var_args = is_var_args;
assert(source_node->type == NodeTypeFnProto);
for (size_t i = 0; i < source_node->data.fn_proto.params.length; i += 1) {
size_t param_count = source_node->data.fn_proto.params.length;
if (is_var_args) param_count -= 1;
for (size_t i = 0; i < param_count; i += 1) {
ir_ref_instruction(param_types[i], irb->current_basic_block);
}
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
size_t param_count = node->data.fn_proto.params.length;
IrInstruction **param_types = allocate<IrInstruction*>(param_count);
bool is_var_args = false;
for (size_t i = 0; i < param_count; i += 1) {
AstNode *param_node = node->data.fn_proto.params.at(i);
if (param_node->data.param_decl.is_var_args) {
is_var_args = true;
break;
}
AstNode *type_node = param_node->data.param_decl.type;
IrInstruction *type_value = ir_gen_node(irb, type_node, parent_scope);
if (type_value == irb->codegen->invalid_instruction)
@ -5856,7 +5864,7 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
if (return_type == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
return ir_build_fn_proto(irb, parent_scope, node, param_types, return_type);
return ir_build_fn_proto(irb, parent_scope, node, param_types, return_type, is_var_args);
}
static 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
}
if (fn_type->data.fn.is_generic) {
assert(fn_entry);
if (!fn_entry) {
ir_add_error(ira, call_instruction->fn_ref,
buf_sprintf("calling a generic function requires compile-time known function value"));
return ira->codegen->builtin_types.entry_invalid;
}
// Count the arguments of the function type id we are creating
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
AstNode *param_node = proto_node->data.fn_proto.params.at(fn_type_id.next_param_index);
assert(param_node->type == NodeTypeParamDecl);
bool param_is_var_args = param_node->data.param_decl.is_var_args;
if (param_is_var_args) {
if (fn_type_id.is_extern) {
fn_type_id.param_count = fn_type_id.next_param_index;
continue;
} else {
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
out_val->data.x_type = get_generic_fn_type(ira->codegen, &fn_type_id);
return ira->codegen->builtin_types.entry_type;
}
}
IrInstruction *param_type_value = instruction->param_types[fn_type_id.next_param_index]->other;
FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index];

View File

@ -1892,4 +1892,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
\\}
,
".tmp_source.zig:3:9: error: cannot goto out of defer expression");
cases.add("calling a var args function only known at runtime",
\\var foos = []fn(...) { foo1, foo2 };
\\
\\fn foo1(args: ...) {}
\\fn foo2(args: ...) {}
\\
\\pub fn main() -> %void {
\\ foos[0]();
\\}
,
".tmp_source.zig:7:9: error: calling a generic function requires compile-time known function value");
}