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 {
11281128
11291129struct FnTableEntry {
11301130 LLVMValueRef llvm_value;
1131 const char *llvm_name;
11311132 AstNode *proto_node;
11321133 AstNode *body_node;
11331134 ScopeFnDef *fndef_scope; // parent should be the top level decls or container decls
......@@ -1501,6 +1502,8 @@ struct CodeGen {
15011502
15021503 Buf *cache_dir;
15031504 Buf *out_h_path;
1505
1506 ZigList<FnTableEntry *> inline_fns;
15041507};
15051508
15061509enum VarLinkage {
src/codegen.cpp+28-10
......@@ -353,10 +353,12 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
353353 } else {
354354 fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
355355 }
356 fn_table_entry->llvm_name = LLVMGetValueName(fn_table_entry->llvm_value);
356357
357358 switch (fn_table_entry->fn_inline) {
358359 case FnInlineAlways:
359360 addLLVMFnAttr(fn_table_entry->llvm_value, "alwaysinline");
361 g->inline_fns.append(fn_table_entry);
360362 break;
361363 case FnInlineNever:
362364 addLLVMFnAttr(fn_table_entry->llvm_value, "noinline");
......@@ -3628,6 +3630,27 @@ static void ensure_cache_dir(CodeGen *g) {
36283630 }
36293631}
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
36313654static void do_code_gen(CodeGen *g) {
36323655 if (g->verbose) {
36333656 fprintf(stderr, "\nCode Generation:\n");
......@@ -3927,6 +3950,8 @@ static void do_code_gen(CodeGen *g) {
39273950 zig_panic("unable to write object file: %s", err_msg);
39283951 }
39293952
3953 validate_inline_fns(g);
3954
39303955 g->link_objects.append(output_path);
39313956}
39323957
......@@ -4719,16 +4744,9 @@ static void gen_root_source(CodeGen *g) {
47194744 }
47204745 }
47214746
4722 if (g->errors.length == 0) {
4723 if (g->verbose) {
4724 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);
4747 report_errors_and_maybe_exit(g);
4748 if (g->verbose) {
4749 fprintf(stderr, "OK\n");
47324750 }
47334751
47344752}
test/compile_errors.zig+25
......@@ -1684,4 +1684,29 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
16841684 \\fn bar() -> ?i32 { 1 }
16851685 ,
16861686 ".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");
16871712}