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
10331033 AstNode *param_node = fn_proto->params.at(fn_type_id.next_param_index);
10341034 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;
10371037 bool param_is_var_args = param_node->data.param_decl.is_var_args;
10381038
1039 if (param_is_inline) {
1039 if (param_is_comptime) {
10401040 if (fn_type_id.is_extern) {
10411041 add_node_error(g, param_node,
10421042 buf_sprintf("comptime parameter not allowed in extern function"));
......@@ -2507,7 +2507,10 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *
25072507 if (expected_type->data.fn.fn_type_id.is_var_args != actual_type->data.fn.fn_type_id.is_var_args) {
25082508 return false;
25092509 }
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 &&
25112514 actual_type->data.fn.fn_type_id.return_type->id != TypeTableEntryIdUnreachable &&
25122515 !types_match_const_cast_only(
25132516 expected_type->data.fn.fn_type_id.return_type,
......@@ -2518,12 +2521,12 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *
25182521 if (expected_type->data.fn.fn_type_id.param_count != actual_type->data.fn.fn_type_id.param_count) {
25192522 return false;
25202523 }
2521 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 }
2524 if (expected_type->data.fn.fn_type_id.next_param_index != actual_type->data.fn.fn_type_id.next_param_index) {
2525 return false;
2526 }
2527 assert(expected_type->data.fn.is_generic ||
2528 expected_type->data.fn.fn_type_id.next_param_index == expected_type->data.fn.fn_type_id.param_count);
2529 for (size_t i = 0; i < expected_type->data.fn.fn_type_id.next_param_index; i += 1) {
25272530 // note it's reversed for parameters
25282531 FnTypeParamInfo *actual_param_info = &actual_type->data.fn.fn_type_id.param_info[i];
25292532 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
1308913089 }
1309013090 }
1309113091 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
1309313095 FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index];
1309413096 param_info->is_noalias = param_node->data.param_decl.is_noalias;
1309513097 param_info->type = ir_resolve_type(ira, param_type_value);
1309613098 if (type_is_invalid(param_info->type))
1309713099 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 }
1309813106 }
1309913107
1310013108 IrInstruction *return_type_value = instruction->return_type->other;
test/cases/generics.zig+24-12
......@@ -1,6 +1,6 @@
11const assert = @import("std").debug.assert;
22
3test "simpleGenericFn" {
3test "simple generic fn" {
44 assert(max(i32, 3, -1) == 3);
55 assert(max(f32, 0.123, 0.456) == 0.456);
66 assert(add(2, 3) == 5);
......@@ -15,7 +15,7 @@ fn add(comptime a: i32, b: i32) -> i32 {
1515}
1616
1717const the_max = max(u32, 1234, 5678);
18test "compileTimeGenericEval" {
18test "compile time generic eval" {
1919 assert(the_max == 5678);
2020}
2121
......@@ -31,21 +31,22 @@ fn sameButWithFloats(a: f64, b: f64) -> f64 {
3131 max(f64, a, b)
3232}
3333
34test "fnWithInlineArgs" {
34test "fn with comptime args" {
3535 assert(gimmeTheBigOne(1234, 5678) == 5678);
3636 assert(shouldCallSameInstance(34, 12) == 34);
3737 assert(sameButWithFloats(0.43, 0.49) == 0.49);
3838}
3939
4040
41test "varParams" {
41test "var params" {
4242 assert(max_i32(12, 34) == 34);
4343 assert(max_f64(1.2, 3.4) == 3.4);
4444}
4545
46// TODO `_`
47const _1 = assert(max_i32(12, 34) == 34);
48const _2 = assert(max_f64(1.2, 3.4) == 3.4);
46comptime {
47 assert(max_i32(12, 34) == 34);
48 assert(max_f64(1.2, 3.4) == 3.4);
49}
4950
5051fn max_var(a: var, b: var) -> @typeOf(a + b) {
5152 if (a > b) a else b
......@@ -72,7 +73,7 @@ pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) -> type {
7273 }
7374}
7475
75test "functionWithReturnTypeType" {
76test "function with return type type" {
7677 var list: List(i32) = undefined;
7778 var list2: List(i32) = undefined;
7879 list.length = 10;
......@@ -82,7 +83,7 @@ test "functionWithReturnTypeType" {
8283}
8384
8485
85test "genericStruct" {
86test "generic struct" {
8687 var a1 = GenNode(i32) {.value = 13, .next = null,};
8788 var b1 = GenNode(bool) {.value = true, .next = null,};
8889 assert(a1.value == 13);
......@@ -97,7 +98,7 @@ fn GenNode(comptime T: type) -> type {
9798 }
9899}
99100
100test "constDeclsInStruct" {
101test "const decls in struct" {
101102 assert(GenericDataThing(3).count_plus_one == 4);
102103}
103104fn GenericDataThing(comptime count: isize) -> type {
......@@ -107,7 +108,7 @@ fn GenericDataThing(comptime count: isize) -> type {
107108}
108109
109110
110test "useGenericParamInGenericParam" {
111test "use generic param in generic param" {
111112 assert(aGenericFn(i32, 3, 4) == 7);
112113}
113114fn 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 {
115116}
116117
117118
118test "genericFnWithImplicitCast" {
119test "generic fn with implicit cast" {
119120 assert(getFirstByte(u8, []u8 {13}) == 13);
120121 assert(getFirstByte(u16, []u16 {0, 13}) == 0);
121122}
......@@ -123,3 +124,14 @@ fn getByte(ptr: ?&const u8) -> u8 {*??ptr}
123124fn getFirstByte(comptime T: type, mem: []const T) -> u8 {
124125 getByte(@ptrCast(&const u8, &mem[0]))
125126}
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 {
5454 }
5555 return args.len;
5656}
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) {
19041904 \\}
19051905 ,
19061906 ".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");
19071919}