authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-05-26 14:39:18-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-05-26 14:39:18-04:00
logc42c91ee7c630d47e6adc0a940b5f10bbe04d13a
treee953816629530d2d532c097cbac3bb846e51763f
parentfcdd808c5c1b866c2582a17839a53ce7bbbb78d6

fix segfault with array of generic functions

closes #377

5 files changed, 67 insertions(+), 21 deletions(-)

src/analyze.cpp+12-9
...@@ -1033,10 +1033,10 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c...@@ -1033,10 +1033,10 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
1033 AstNode *param_node = fn_proto->params.at(fn_type_id.next_param_index);1033 AstNode *param_node = fn_proto->params.at(fn_type_id.next_param_index);
1034 assert(param_node->type == NodeTypeParamDecl);1034 assert(param_node->type == NodeTypeParamDecl);
10351035
1036 bool param_is_inline = param_node->data.param_decl.is_inline;1036 bool param_is_comptime = param_node->data.param_decl.is_inline;
1037 bool param_is_var_args = param_node->data.param_decl.is_var_args;1037 bool param_is_var_args = param_node->data.param_decl.is_var_args;
10381038
1039 if (param_is_inline) {1039 if (param_is_comptime) {
1040 if (fn_type_id.is_extern) {1040 if (fn_type_id.is_extern) {
1041 add_node_error(g, param_node,1041 add_node_error(g, param_node,
1042 buf_sprintf("comptime parameter not allowed in extern function"));1042 buf_sprintf("comptime parameter not allowed in extern function"));
...@@ -2507,7 +2507,10 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *...@@ -2507,7 +2507,10 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *
2507 if (expected_type->data.fn.fn_type_id.is_var_args != actual_type->data.fn.fn_type_id.is_var_args) {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;2508 return false;
2509 }2509 }
2510 if (!expected_type->data.fn.fn_type_id.is_var_args && 2510 if (expected_type->data.fn.is_generic != actual_type->data.fn.is_generic) {
2511 return false;
2512 }
2513 if (!expected_type->data.fn.is_generic &&
2511 actual_type->data.fn.fn_type_id.return_type->id != TypeTableEntryIdUnreachable &&2514 actual_type->data.fn.fn_type_id.return_type->id != TypeTableEntryIdUnreachable &&
2512 !types_match_const_cast_only(2515 !types_match_const_cast_only(
2513 expected_type->data.fn.fn_type_id.return_type,2516 expected_type->data.fn.fn_type_id.return_type,
...@@ -2518,12 +2521,12 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *...@@ -2518,12 +2521,12 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *
2518 if (expected_type->data.fn.fn_type_id.param_count != actual_type->data.fn.fn_type_id.param_count) {2521 if (expected_type->data.fn.fn_type_id.param_count != actual_type->data.fn.fn_type_id.param_count) {
2519 return false;2522 return false;
2520 }2523 }
2521 for (size_t i = 0; i < expected_type->data.fn.fn_type_id.param_count; i += 1) {2524 if (expected_type->data.fn.fn_type_id.next_param_index != actual_type->data.fn.fn_type_id.next_param_index) {
2522 if (i == expected_type->data.fn.fn_type_id.param_count - 1 &&2525 return false;
2523 expected_type->data.fn.fn_type_id.is_var_args)2526 }
2524 {2527 assert(expected_type->data.fn.is_generic ||
2525 continue;2528 expected_type->data.fn.fn_type_id.next_param_index == expected_type->data.fn.fn_type_id.param_count);
2526 }2529 for (size_t i = 0; i < expected_type->data.fn.fn_type_id.next_param_index; i += 1) {
2527 // note it's reversed for parameters2530 // note it's reversed for parameters
2528 FnTypeParamInfo *actual_param_info = &actual_type->data.fn.fn_type_id.param_info[i];2531 FnTypeParamInfo *actual_param_info = &actual_type->data.fn.fn_type_id.param_info[i];
2529 FnTypeParamInfo *expected_param_info = &expected_type->data.fn.fn_type_id.param_info[i];2532 FnTypeParamInfo *expected_param_info = &expected_type->data.fn.fn_type_id.param_info[i];
src/ir.cpp+8
...@@ -13089,12 +13089,20 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc...@@ -13089,12 +13089,20 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc
13089 }13089 }
13090 }13090 }
13091 IrInstruction *param_type_value = instruction->param_types[fn_type_id.next_param_index]->other;13091 IrInstruction *param_type_value = instruction->param_types[fn_type_id.next_param_index]->other;
13092 if (type_is_invalid(param_type_value->value.type))
13093 return ira->codegen->builtin_types.entry_invalid;
1309213094
13093 FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index];13095 FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index];
13094 param_info->is_noalias = param_node->data.param_decl.is_noalias;13096 param_info->is_noalias = param_node->data.param_decl.is_noalias;
13095 param_info->type = ir_resolve_type(ira, param_type_value);13097 param_info->type = ir_resolve_type(ira, param_type_value);
13096 if (type_is_invalid(param_info->type))13098 if (type_is_invalid(param_info->type))
13097 return ira->codegen->builtin_types.entry_invalid;13099 return ira->codegen->builtin_types.entry_invalid;
13100
13101 if (param_info->type->id == TypeTableEntryIdVar) {
13102 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
13103 out_val->data.x_type = get_generic_fn_type(ira->codegen, &fn_type_id);
13104 return ira->codegen->builtin_types.entry_type;
13105 }
13098 }13106 }
1309913107
13100 IrInstruction *return_type_value = instruction->return_type->other;13108 IrInstruction *return_type_value = instruction->return_type->other;
test/cases/generics.zig+24-12
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const assert = @import("std").debug.assert;1const assert = @import("std").debug.assert;
22
3test "simpleGenericFn" {3test "simple generic fn" {
4 assert(max(i32, 3, -1) == 3);4 assert(max(i32, 3, -1) == 3);
5 assert(max(f32, 0.123, 0.456) == 0.456);5 assert(max(f32, 0.123, 0.456) == 0.456);
6 assert(add(2, 3) == 5);6 assert(add(2, 3) == 5);
...@@ -15,7 +15,7 @@ fn add(comptime a: i32, b: i32) -> i32 {...@@ -15,7 +15,7 @@ fn add(comptime a: i32, b: i32) -> i32 {
15}15}
1616
17const the_max = max(u32, 1234, 5678);17const the_max = max(u32, 1234, 5678);
18test "compileTimeGenericEval" {18test "compile time generic eval" {
19 assert(the_max == 5678);19 assert(the_max == 5678);
20}20}
2121
...@@ -31,21 +31,22 @@ fn sameButWithFloats(a: f64, b: f64) -> f64 {...@@ -31,21 +31,22 @@ fn sameButWithFloats(a: f64, b: f64) -> f64 {
31 max(f64, a, b)31 max(f64, a, b)
32}32}
3333
34test "fnWithInlineArgs" {34test "fn with comptime args" {
35 assert(gimmeTheBigOne(1234, 5678) == 5678);35 assert(gimmeTheBigOne(1234, 5678) == 5678);
36 assert(shouldCallSameInstance(34, 12) == 34);36 assert(shouldCallSameInstance(34, 12) == 34);
37 assert(sameButWithFloats(0.43, 0.49) == 0.49);37 assert(sameButWithFloats(0.43, 0.49) == 0.49);
38}38}
3939
4040
41test "varParams" {41test "var params" {
42 assert(max_i32(12, 34) == 34);42 assert(max_i32(12, 34) == 34);
43 assert(max_f64(1.2, 3.4) == 3.4);43 assert(max_f64(1.2, 3.4) == 3.4);
44}44}
4545
46// TODO `_`46comptime {
47const _1 = assert(max_i32(12, 34) == 34);47 assert(max_i32(12, 34) == 34);
48const _2 = assert(max_f64(1.2, 3.4) == 3.4);48 assert(max_f64(1.2, 3.4) == 3.4);
49}
4950
50fn max_var(a: var, b: var) -> @typeOf(a + b) {51fn max_var(a: var, b: var) -> @typeOf(a + b) {
51 if (a > b) a else b52 if (a > b) a else b
...@@ -72,7 +73,7 @@ pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) -> type {...@@ -72,7 +73,7 @@ pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) -> type {
72 }73 }
73}74}
7475
75test "functionWithReturnTypeType" {76test "function with return type type" {
76 var list: List(i32) = undefined;77 var list: List(i32) = undefined;
77 var list2: List(i32) = undefined;78 var list2: List(i32) = undefined;
78 list.length = 10;79 list.length = 10;
...@@ -82,7 +83,7 @@ test "functionWithReturnTypeType" {...@@ -82,7 +83,7 @@ test "functionWithReturnTypeType" {
82}83}
8384
8485
85test "genericStruct" {86test "generic struct" {
86 var a1 = GenNode(i32) {.value = 13, .next = null,};87 var a1 = GenNode(i32) {.value = 13, .next = null,};
87 var b1 = GenNode(bool) {.value = true, .next = null,};88 var b1 = GenNode(bool) {.value = true, .next = null,};
88 assert(a1.value == 13);89 assert(a1.value == 13);
...@@ -97,7 +98,7 @@ fn GenNode(comptime T: type) -> type {...@@ -97,7 +98,7 @@ fn GenNode(comptime T: type) -> type {
97 }98 }
98}99}
99100
100test "constDeclsInStruct" {101test "const decls in struct" {
101 assert(GenericDataThing(3).count_plus_one == 4);102 assert(GenericDataThing(3).count_plus_one == 4);
102}103}
103fn GenericDataThing(comptime count: isize) -> type {104fn GenericDataThing(comptime count: isize) -> type {
...@@ -107,7 +108,7 @@ fn GenericDataThing(comptime count: isize) -> type {...@@ -107,7 +108,7 @@ fn GenericDataThing(comptime count: isize) -> type {
107}108}
108109
109110
110test "useGenericParamInGenericParam" {111test "use generic param in generic param" {
111 assert(aGenericFn(i32, 3, 4) == 7);112 assert(aGenericFn(i32, 3, 4) == 7);
112}113}
113fn aGenericFn(comptime T: type, comptime a: T, b: T) -> T {114fn aGenericFn(comptime T: type, comptime a: T, b: T) -> T {
...@@ -115,7 +116,7 @@ fn aGenericFn(comptime T: type, comptime a: T, b: T) -> T {...@@ -115,7 +116,7 @@ fn aGenericFn(comptime T: type, comptime a: T, b: T) -> T {
115}116}
116117
117118
118test "genericFnWithImplicitCast" {119test "generic fn with implicit cast" {
119 assert(getFirstByte(u8, []u8 {13}) == 13);120 assert(getFirstByte(u8, []u8 {13}) == 13);
120 assert(getFirstByte(u16, []u16 {0, 13}) == 0);121 assert(getFirstByte(u16, []u16 {0, 13}) == 0);
121}122}
...@@ -123,3 +124,14 @@ fn getByte(ptr: ?&const u8) -> u8 {*??ptr}...@@ -123,3 +124,14 @@ fn getByte(ptr: ?&const u8) -> u8 {*??ptr}
123fn getFirstByte(comptime T: type, mem: []const T) -> u8 {124fn getFirstByte(comptime T: type, mem: []const T) -> u8 {
124 getByte(@ptrCast(&const u8, &mem[0]))125 getByte(@ptrCast(&const u8, &mem[0]))
125}126}
127
128
129const foos = []fn(var) -> bool { foo1, foo2 };
130
131fn foo1(arg: var) -> bool { arg }
132fn foo2(arg: var) -> bool { !arg }
133
134test "array of generic fns" {
135 assert(foos[0](true));
136 assert(!foos[1](true));
137}
test/cases/var_args.zig+11
...@@ -54,3 +54,14 @@ fn extraFn(extra: u32, args: ...) -> usize {...@@ -54,3 +54,14 @@ fn extraFn(extra: u32, args: ...) -> usize {
54 }54 }
55 return args.len;55 return args.len;
56}56}
57
58
59const foos = []fn(...) -> bool { foo1, foo2 };
60
61fn foo1(args: ...) -> bool { true }
62fn foo2(args: ...) -> bool { false }
63
64test "array of var args functions" {
65 assert(foos[0]());
66 assert(!foos[1]());
67}
test/compile_errors.zig+12
...@@ -1904,4 +1904,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) {...@@ -1904,4 +1904,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
1904 \\}1904 \\}
1905 ,1905 ,
1906 ".tmp_source.zig:7:9: error: calling a generic function requires compile-time known function value");1906 ".tmp_source.zig:7:9: error: calling a generic function requires compile-time known function value");
1907
1908 cases.add("calling a generic function only known at runtime",
1909 \\var foos = []fn(var) { foo1, foo2 };
1910 \\
1911 \\fn foo1(arg: var) {}
1912 \\fn foo2(arg: var) {}
1913 \\
1914 \\pub fn main() -> %void {
1915 \\ foos[0](true);
1916 \\}
1917 ,
1918 ".tmp_source.zig:7:9: error: calling a generic function requires compile-time known function value");
1907}1919}