authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-05-04 15:00:25-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-05-04 15:11:24-04:00
log866c841dd8770bcc12af0aaf946c80819f5e0092
treec6d635e36c0c4b63019e098ec759b671d6e7ddf6
parent5c094d7390a7225f942032992b6070dcb6b9f761

add compile error when unable to inline a function

See #38

3 files changed, 56 insertions(+), 10 deletions(-)

src/all_types.hpp+3
...@@ -1128,6 +1128,7 @@ enum FnInline {...@@ -1128,6 +1128,7 @@ enum FnInline {
11281128
1129struct FnTableEntry {1129struct FnTableEntry {
1130 LLVMValueRef llvm_value;1130 LLVMValueRef llvm_value;
1131 const char *llvm_name;
1131 AstNode *proto_node;1132 AstNode *proto_node;
1132 AstNode *body_node;1133 AstNode *body_node;
1133 ScopeFnDef *fndef_scope; // parent should be the top level decls or container decls1134 ScopeFnDef *fndef_scope; // parent should be the top level decls or container decls
...@@ -1501,6 +1502,8 @@ struct CodeGen {...@@ -1501,6 +1502,8 @@ struct CodeGen {
15011502
1502 Buf *cache_dir;1503 Buf *cache_dir;
1503 Buf *out_h_path;1504 Buf *out_h_path;
1505
1506 ZigList<FnTableEntry *> inline_fns;
1504};1507};
15051508
1506enum VarLinkage {1509enum VarLinkage {
src/codegen.cpp+28-10
...@@ -353,10 +353,12 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {...@@ -353,10 +353,12 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
353 } else {353 } else {
354 fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);354 fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
355 }355 }
356 fn_table_entry->llvm_name = LLVMGetValueName(fn_table_entry->llvm_value);
356357
357 switch (fn_table_entry->fn_inline) {358 switch (fn_table_entry->fn_inline) {
358 case FnInlineAlways:359 case FnInlineAlways:
359 addLLVMFnAttr(fn_table_entry->llvm_value, "alwaysinline");360 addLLVMFnAttr(fn_table_entry->llvm_value, "alwaysinline");
361 g->inline_fns.append(fn_table_entry);
360 break;362 break;
361 case FnInlineNever:363 case FnInlineNever:
362 addLLVMFnAttr(fn_table_entry->llvm_value, "noinline");364 addLLVMFnAttr(fn_table_entry->llvm_value, "noinline");
...@@ -3628,6 +3630,27 @@ static void ensure_cache_dir(CodeGen *g) {...@@ -3628,6 +3630,27 @@ static void ensure_cache_dir(CodeGen *g) {
3628 }3630 }
3629}3631}
36303632
3633static void report_errors_and_maybe_exit(CodeGen *g) {
3634 if (g->errors.length != 0) {
3635 for (size_t i = 0; i < g->errors.length; i += 1) {
3636 ErrorMsg *err = g->errors.at(i);
3637 print_err_msg(err, g->err_color);
3638 }
3639 exit(1);
3640 }
3641}
3642
3643static void validate_inline_fns(CodeGen *g) {
3644 for (size_t i = 0; i < g->inline_fns.length; i += 1) {
3645 FnTableEntry *fn_entry = g->inline_fns.at(i);
3646 LLVMValueRef fn_val = LLVMGetNamedFunction(g->module, fn_entry->llvm_name);
3647 if (fn_val != nullptr) {
3648 add_node_error(g, fn_entry->proto_node, buf_sprintf("unable to inline function"));
3649 }
3650 }
3651 report_errors_and_maybe_exit(g);
3652}
3653
3631static void do_code_gen(CodeGen *g) {3654static void do_code_gen(CodeGen *g) {
3632 if (g->verbose) {3655 if (g->verbose) {
3633 fprintf(stderr, "\nCode Generation:\n");3656 fprintf(stderr, "\nCode Generation:\n");
...@@ -3927,6 +3950,8 @@ static void do_code_gen(CodeGen *g) {...@@ -3927,6 +3950,8 @@ static void do_code_gen(CodeGen *g) {
3927 zig_panic("unable to write object file: %s", err_msg);3950 zig_panic("unable to write object file: %s", err_msg);
3928 }3951 }
39293952
3953 validate_inline_fns(g);
3954
3930 g->link_objects.append(output_path);3955 g->link_objects.append(output_path);
3931}3956}
39323957
...@@ -4719,16 +4744,9 @@ static void gen_root_source(CodeGen *g) {...@@ -4719,16 +4744,9 @@ static void gen_root_source(CodeGen *g) {
4719 }4744 }
4720 }4745 }
47214746
4722 if (g->errors.length == 0) {4747 report_errors_and_maybe_exit(g);
4723 if (g->verbose) {4748 if (g->verbose) {
4724 fprintf(stderr, "OK\n");4749 fprintf(stderr, "OK\n");
4725 }
4726 } else {
4727 for (size_t i = 0; i < g->errors.length; i += 1) {
4728 ErrorMsg *err = g->errors.at(i);
4729 print_err_msg(err, g->err_color);
4730 }
4731 exit(1);
4732 }4750 }
47334751
4734}4752}
test/compile_errors.zig+25
...@@ -1684,4 +1684,29 @@ pub fn addCases(cases: &tests.CompileErrorContext) {...@@ -1684,4 +1684,29 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
1684 \\fn bar() -> ?i32 { 1 }1684 \\fn bar() -> ?i32 { 1 }
1685 ,1685 ,
1686 ".tmp_source.zig:2:15: error: expected error union type, found '?i32'");1686 ".tmp_source.zig:2:15: error: expected error union type, found '?i32'");
1687
1688 cases.add("inline fn calls itself indirectly",
1689 \\export fn foo() {
1690 \\ bar();
1691 \\}
1692 \\inline fn bar() {
1693 \\ baz();
1694 \\ quux();
1695 \\}
1696 \\inline fn baz() {
1697 \\ bar();
1698 \\ quux();
1699 \\}
1700 \\extern fn quux();
1701 ,
1702 ".tmp_source.zig:4:8: error: unable to inline function");
1703
1704 cases.add("save reference to inline function",
1705 \\export fn foo() {
1706 \\ quux(usize(bar));
1707 \\}
1708 \\inline fn bar() { }
1709 \\extern fn quux(usize);
1710 ,
1711 ".tmp_source.zig:4:8: error: unable to inline function");
1687}1712}