| author | |
| committer | |
| log | 3a326d50051ad8b65639e5e2bbe45e41a8b35591 |
| tree | 797dc5661ae401c4d75971fb8c722a8834cfb2c9 |
| parent | 4c50606b9d41c2c3d9f25dc8bf0848e30e338f6e |
See #147 files changed, 110 insertions(+), 137 deletions(-)
src/all_types.hpp+2-6| ... | ... | @@ -793,11 +793,6 @@ struct LabelTableEntry { |
| 793 | 793 | bool entered_from_fallthrough; |
| 794 | 794 | }; |
| 795 | 795 | |
| 796 | enum FnAttrId { | |
| 797 | FnAttrIdNaked, | |
| 798 | FnAttrIdAlwaysInline, | |
| 799 | }; | |
| 800 | ||
| 801 | 796 | struct FnTableEntry { |
| 802 | 797 | LLVMValueRef fn_value; |
| 803 | 798 | AstNode *proto_node; |
| ... | ... | @@ -806,7 +801,8 @@ struct FnTableEntry { |
| 806 | 801 | bool internal_linkage; |
| 807 | 802 | unsigned calling_convention; |
| 808 | 803 | ImportTableEntry *import_entry; |
| 809 | ZigList<FnAttrId> fn_attr_list; | |
| 804 | bool is_naked; | |
| 805 | bool is_inline; | |
| 810 | 806 | // Required to be a pre-order traversal of the AST. (parents must come before children) |
| 811 | 807 | ZigList<BlockContext *> all_block_contexts; |
| 812 | 808 | TypeTableEntry *member_of_struct; |
src/analyze.cpp+90-30| ... | ... | @@ -346,18 +346,19 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 346 | 346 | ImportTableEntry *import) |
| 347 | 347 | { |
| 348 | 348 | assert(node->type == NodeTypeFnProto); |
| 349 | AstNodeFnProto *fn_proto = &node->data.fn_proto; | |
| 349 | 350 | |
| 350 | for (int i = 0; i < node->data.fn_proto.directives->length; i += 1) { | |
| 351 | AstNode *directive_node = node->data.fn_proto.directives->at(i); | |
| 351 | for (int i = 0; i < fn_proto->directives->length; i += 1) { | |
| 352 | AstNode *directive_node = fn_proto->directives->at(i); | |
| 352 | 353 | Buf *name = &directive_node->data.directive.name; |
| 353 | 354 | |
| 354 | 355 | if (buf_eql_str(name, "attribute")) { |
| 355 | 356 | Buf *attr_name = &directive_node->data.directive.param; |
| 356 | 357 | if (fn_table_entry->fn_def_node) { |
| 357 | 358 | if (buf_eql_str(attr_name, "naked")) { |
| 358 | fn_table_entry->fn_attr_list.append(FnAttrIdNaked); | |
| 359 | fn_table_entry->is_naked = true; | |
| 359 | 360 | } else if (buf_eql_str(attr_name, "inline")) { |
| 360 | fn_table_entry->fn_attr_list.append(FnAttrIdAlwaysInline); | |
| 361 | fn_table_entry->is_inline = true; | |
| 361 | 362 | } else { |
| 362 | 363 | add_node_error(g, directive_node, |
| 363 | 364 | buf_sprintf("invalid function attribute: '%s'", buf_ptr(name))); |
| ... | ... | @@ -382,38 +383,100 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 382 | 383 | |
| 383 | 384 | buf_resize(&fn_type->name, 0); |
| 384 | 385 | buf_appendf(&fn_type->name, "fn("); |
| 386 | int gen_param_count = 0; | |
| 387 | LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(param_count); | |
| 388 | LLVMZigDIType **param_di_types = allocate<LLVMZigDIType*>(1 + param_count); | |
| 385 | 389 | for (int i = 0; i < param_count; i += 1) { |
| 386 | 390 | AstNode *child = node->data.fn_proto.params.at(i); |
| 387 | 391 | assert(child->type == NodeTypeParamDecl); |
| 388 | 392 | TypeTableEntry *type_entry = analyze_type_expr(g, import, import->block_context, |
| 389 | 393 | child->data.param_decl.type); |
| 390 | fn_table_entry->type_entry->data.fn.param_types[i] = type_entry; | |
| 391 | ||
| 392 | buf_appendf(&fn_type->name, "%s", buf_ptr(&type_entry->name)); | |
| 393 | ||
| 394 | if (i + 1 < param_count) { | |
| 395 | buf_appendf(&fn_type->name, ", "); | |
| 396 | } | |
| 394 | fn_type->data.fn.param_types[i] = type_entry; | |
| 397 | 395 | |
| 398 | 396 | if (type_entry->id == TypeTableEntryIdUnreachable) { |
| 399 | 397 | add_node_error(g, child->data.param_decl.type, |
| 400 | 398 | buf_sprintf("parameter of type 'unreachable' not allowed")); |
| 401 | } else if (type_entry->id == TypeTableEntryIdVoid) { | |
| 402 | if (node->data.fn_proto.visib_mod == VisibModExport) { | |
| 403 | add_node_error(g, child->data.param_decl.type, | |
| 404 | buf_sprintf("parameter of type 'void' not allowed on exported functions")); | |
| 405 | } | |
| 399 | fn_proto->skip = true; | |
| 400 | } else if (type_entry->id == TypeTableEntryIdInvalid) { | |
| 401 | fn_proto->skip = true; | |
| 402 | } | |
| 403 | ||
| 404 | if (!fn_proto->skip && type_entry->size_in_bits > 0) { | |
| 405 | const char *comma = (gen_param_count == 0) ? "" : ", "; | |
| 406 | buf_appendf(&fn_type->name, "%s%s", comma, buf_ptr(&type_entry->name)); | |
| 407 | ||
| 408 | TypeTableEntry *gen_type = handle_is_ptr(type_entry) ? | |
| 409 | get_pointer_to_type(g, type_entry, true) : type_entry; | |
| 410 | gen_param_types[gen_param_count] = gen_type->type_ref; | |
| 411 | ||
| 412 | gen_param_count += 1; | |
| 413 | ||
| 414 | // after the gen_param_count += 1 because 0 is the return type | |
| 415 | param_di_types[gen_param_count] = gen_type->di_type; | |
| 406 | 416 | } |
| 407 | 417 | } |
| 408 | 418 | |
| 409 | 419 | TypeTableEntry *return_type = analyze_type_expr(g, import, import->block_context, |
| 410 | 420 | node->data.fn_proto.return_type); |
| 411 | fn_table_entry->type_entry->data.fn.return_type = return_type; | |
| 421 | fn_type->data.fn.return_type = return_type; | |
| 422 | if (return_type->id == TypeTableEntryIdInvalid) { | |
| 423 | fn_proto->skip = true; | |
| 424 | } | |
| 412 | 425 | |
| 413 | 426 | buf_appendf(&fn_type->name, ")"); |
| 414 | 427 | if (return_type->id != TypeTableEntryIdVoid) { |
| 415 | 428 | buf_appendf(&fn_type->name, " %s", buf_ptr(&return_type->name)); |
| 416 | 429 | } |
| 430 | ||
| 431 | if (fn_proto->skip) { | |
| 432 | return; | |
| 433 | } | |
| 434 | ||
| 435 | fn_type->type_ref = LLVMFunctionType(return_type->type_ref, gen_param_types, gen_param_count, | |
| 436 | fn_proto->is_var_args); | |
| 437 | ||
| 438 | fn_table_entry->fn_value = LLVMAddFunction(g->module, buf_ptr(&fn_table_entry->symbol_name), | |
| 439 | fn_table_entry->type_entry->type_ref); | |
| 440 | ||
| 441 | if (fn_table_entry->is_inline) { | |
| 442 | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMAlwaysInlineAttribute); | |
| 443 | } | |
| 444 | if (fn_table_entry->is_naked) { | |
| 445 | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNakedAttribute); | |
| 446 | } | |
| 447 | ||
| 448 | LLVMSetLinkage(fn_table_entry->fn_value, fn_table_entry->internal_linkage ? | |
| 449 | LLVMInternalLinkage : LLVMExternalLinkage); | |
| 450 | ||
| 451 | if (return_type->id == TypeTableEntryIdUnreachable) { | |
| 452 | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoReturnAttribute); | |
| 453 | } | |
| 454 | LLVMSetFunctionCallConv(fn_table_entry->fn_value, fn_table_entry->calling_convention); | |
| 455 | if (!fn_table_entry->is_extern) { | |
| 456 | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoUnwindAttribute); | |
| 457 | } | |
| 458 | ||
| 459 | param_di_types[0] = return_type->di_type; | |
| 460 | LLVMZigDISubroutineType *di_sub_type = LLVMZigCreateSubroutineType(g->dbuilder, import->di_file, | |
| 461 | param_di_types, gen_param_count + 1, 0); | |
| 462 | ||
| 463 | // Add debug info. | |
| 464 | unsigned line_number = node->line + 1; | |
| 465 | unsigned scope_line = line_number; | |
| 466 | bool is_definition = fn_table_entry->fn_def_node != nullptr; | |
| 467 | unsigned flags = 0; | |
| 468 | bool is_optimized = g->build_type == CodeGenBuildTypeRelease; | |
| 469 | LLVMZigDISubprogram *subprogram = LLVMZigCreateFunction(g->dbuilder, | |
| 470 | import->block_context->di_scope, buf_ptr(&fn_table_entry->symbol_name), "", | |
| 471 | import->di_file, line_number, | |
| 472 | di_sub_type, fn_table_entry->internal_linkage, | |
| 473 | is_definition, scope_line, flags, is_optimized, fn_table_entry->fn_value); | |
| 474 | fn_type->di_type = LLVMZigSubroutineToType(di_sub_type); | |
| 475 | if (fn_table_entry->fn_def_node) { | |
| 476 | BlockContext *context = new_block_context(fn_table_entry->fn_def_node, import->block_context); | |
| 477 | fn_table_entry->fn_def_node->data.fn_def.block_context = context; | |
| 478 | context->di_scope = LLVMZigSubprogramToScope(subprogram); | |
| 479 | } | |
| 417 | 480 | } |
| 418 | 481 | |
| 419 | 482 | static void preview_function_labels(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry) { |
| ... | ... | @@ -724,14 +787,6 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import, |
| 724 | 787 | buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); |
| 725 | 788 | proto_node->data.fn_proto.skip = true; |
| 726 | 789 | skip = true; |
| 727 | } else if (is_pub) { | |
| 728 | // TODO is this else if branch a mistake? | |
| 729 | auto entry = fn_table->maybe_get(proto_name); | |
| 730 | if (entry) { | |
| 731 | add_node_error(g, proto_node, buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); | |
| 732 | proto_node->data.fn_proto.skip = true; | |
| 733 | skip = true; | |
| 734 | } | |
| 735 | 790 | } |
| 736 | 791 | if (!extern_node && proto_node->data.fn_proto.is_var_args) { |
| 737 | 792 | add_node_error(g, proto_node, |
| ... | ... | @@ -775,10 +830,8 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import, |
| 775 | 830 | g->bootstrap_import->fn_table.put(proto_name, fn_table_entry); |
| 776 | 831 | } |
| 777 | 832 | |
| 778 | resolve_function_proto(g, proto_node, fn_table_entry, import); | |
| 779 | ||
| 780 | ||
| 781 | 833 | proto_node->data.fn_proto.fn_table_entry = fn_table_entry; |
| 834 | resolve_function_proto(g, proto_node, fn_table_entry, import); | |
| 782 | 835 | |
| 783 | 836 | if (fn_def_node) { |
| 784 | 837 | preview_function_labels(g, fn_def_node->data.fn_def.body, fn_table_entry); |
| ... | ... | @@ -3146,8 +3199,7 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo |
| 3146 | 3199 | return; |
| 3147 | 3200 | } |
| 3148 | 3201 | |
| 3149 | BlockContext *context = new_block_context(node, import->block_context); | |
| 3150 | node->data.fn_def.block_context = context; | |
| 3202 | BlockContext *context = node->data.fn_def.block_context; | |
| 3151 | 3203 | |
| 3152 | 3204 | AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto; |
| 3153 | 3205 | bool is_exported = (fn_proto->visib_mod == VisibModExport); |
| ... | ... | @@ -3923,3 +3975,11 @@ TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, int size_in_bits) |
| 3923 | 3975 | TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, int size_in_bits) { |
| 3924 | 3976 | return *get_int_type_ptr(g, is_signed, size_in_bits); |
| 3925 | 3977 | } |
| 3978 | ||
| 3979 | bool handle_is_ptr(TypeTableEntry *type_entry) { | |
| 3980 | return type_entry->id == TypeTableEntryIdStruct || | |
| 3981 | (type_entry->id == TypeTableEntryIdEnum && type_entry->data.enumeration.gen_field_count != 0) || | |
| 3982 | type_entry->id == TypeTableEntryIdMaybe || | |
| 3983 | type_entry->id == TypeTableEntryIdArray; | |
| 3984 | } | |
| 3985 |
src/analyze.hpp+1-1| ... | ... | @@ -23,5 +23,5 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node); |
| 23 | 23 | bool is_node_void_expr(AstNode *node); |
| 24 | 24 | TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, int size_in_bits); |
| 25 | 25 | TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, int size_in_bits); |
| 26 | ||
| 26 | bool handle_is_ptr(TypeTableEntry *type_entry); | |
| 27 | 27 | #endif |
src/codegen.cpp+11-96| ... | ... | @@ -82,29 +82,13 @@ static TypeTableEntry *get_type_for_type_node(AstNode *node) { |
| 82 | 82 | return const_val->data.x_type; |
| 83 | 83 | } |
| 84 | 84 | |
| 85 | static TypeTableEntry *fn_proto_type_from_type_node(CodeGen *g, AstNode *type_node) { | |
| 86 | TypeTableEntry *type_entry = get_type_for_type_node(type_node); | |
| 87 | ||
| 88 | if (type_entry->id == TypeTableEntryIdStruct || type_entry->id == TypeTableEntryIdArray) { | |
| 89 | return get_pointer_to_type(g, type_entry, true); | |
| 90 | } else { | |
| 91 | return type_entry; | |
| 92 | } | |
| 93 | } | |
| 94 | ||
| 95 | static LLVMZigDIType *to_llvm_debug_type(CodeGen *g, AstNode *type_node) { | |
| 96 | TypeTableEntry *type_entry = get_type_for_type_node(type_node); | |
| 97 | return type_entry->di_type; | |
| 98 | } | |
| 99 | ||
| 100 | ||
| 101 | 85 | static bool type_is_unreachable(CodeGen *g, AstNode *type_node) { |
| 102 | 86 | return get_type_for_type_node(type_node)->id == TypeTableEntryIdUnreachable; |
| 103 | 87 | } |
| 104 | 88 | |
| 105 | 89 | static bool is_param_decl_type_void(CodeGen *g, AstNode *param_decl_node) { |
| 106 | 90 | assert(param_decl_node->type == NodeTypeParamDecl); |
| 107 | return get_type_for_type_node(param_decl_node->data.param_decl.type)->id == TypeTableEntryIdVoid; | |
| 91 | return get_type_for_type_node(param_decl_node->data.param_decl.type)->size_in_bits == 0; | |
| 108 | 92 | } |
| 109 | 93 | |
| 110 | 94 | static int count_non_void_params(CodeGen *g, ZigList<AstNode *> *params) { |
| ... | ... | @@ -150,11 +134,14 @@ static TypeTableEntry *get_expr_type(AstNode *node) { |
| 150 | 134 | return expr->type_entry; |
| 151 | 135 | } |
| 152 | 136 | |
| 153 | static bool handle_is_ptr(TypeTableEntry *type_entry) { | |
| 154 | return type_entry->id == TypeTableEntryIdStruct || | |
| 155 | (type_entry->id == TypeTableEntryIdEnum && type_entry->data.enumeration.gen_field_count != 0) || | |
| 156 | type_entry->id == TypeTableEntryIdMaybe || | |
| 157 | type_entry->id == TypeTableEntryIdArray; | |
| 137 | static TypeTableEntry *fn_proto_type_from_type_node(CodeGen *g, AstNode *type_node) { | |
| 138 | TypeTableEntry *type_entry = get_type_for_type_node(type_node); | |
| 139 | ||
| 140 | if (handle_is_ptr(type_entry)) { | |
| 141 | return get_pointer_to_type(g, type_entry, true); | |
| 142 | } else { | |
| 143 | return type_entry; | |
| 144 | } | |
| 158 | 145 | } |
| 159 | 146 | |
| 160 | 147 | static LLVMValueRef gen_number_literal_raw(CodeGen *g, AstNode *source_node, |
| ... | ... | @@ -2121,31 +2108,6 @@ static void build_label_blocks(CodeGen *g, AstNode *block_node) { |
| 2121 | 2108 | |
| 2122 | 2109 | } |
| 2123 | 2110 | |
| 2124 | static LLVMZigDISubroutineType *create_di_function_type(CodeGen *g, AstNodeFnProto *fn_proto, | |
| 2125 | LLVMZigDIFile *di_file) | |
| 2126 | { | |
| 2127 | LLVMZigDIType **types = allocate<LLVMZigDIType*>(1 + fn_proto->params.length); | |
| 2128 | types[0] = to_llvm_debug_type(g, fn_proto->return_type); | |
| 2129 | int types_len = fn_proto->params.length + 1; | |
| 2130 | for (int i = 0; i < fn_proto->params.length; i += 1) { | |
| 2131 | AstNode *param_node = fn_proto->params.at(i); | |
| 2132 | assert(param_node->type == NodeTypeParamDecl); | |
| 2133 | LLVMZigDIType *param_type = to_llvm_debug_type(g, param_node->data.param_decl.type); | |
| 2134 | types[i + 1] = param_type; | |
| 2135 | } | |
| 2136 | return LLVMZigCreateSubroutineType(g->dbuilder, di_file, types, types_len, 0); | |
| 2137 | } | |
| 2138 | ||
| 2139 | static LLVMAttribute to_llvm_fn_attr(FnAttrId attr_id) { | |
| 2140 | switch (attr_id) { | |
| 2141 | case FnAttrIdNaked: | |
| 2142 | return LLVMNakedAttribute; | |
| 2143 | case FnAttrIdAlwaysInline: | |
| 2144 | return LLVMAlwaysInlineAttribute; | |
| 2145 | } | |
| 2146 | zig_unreachable(); | |
| 2147 | } | |
| 2148 | ||
| 2149 | 2111 | static void do_code_gen(CodeGen *g) { |
| 2150 | 2112 | assert(!g->errors.length); |
| 2151 | 2113 | |
| ... | ... | @@ -2172,45 +2134,12 @@ static void do_code_gen(CodeGen *g) { |
| 2172 | 2134 | // Generate function prototypes |
| 2173 | 2135 | for (int fn_proto_i = 0; fn_proto_i < g->fn_protos.length; fn_proto_i += 1) { |
| 2174 | 2136 | FnTableEntry *fn_table_entry = g->fn_protos.at(fn_proto_i); |
| 2175 | ||
| 2176 | 2137 | AstNode *proto_node = fn_table_entry->proto_node; |
| 2177 | 2138 | assert(proto_node->type == NodeTypeFnProto); |
| 2178 | 2139 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; |
| 2179 | 2140 | |
| 2180 | LLVMTypeRef ret_type = get_type_for_type_node(fn_proto->return_type)->type_ref; | |
| 2181 | int param_count = count_non_void_params(g, &fn_proto->params); | |
| 2182 | LLVMTypeRef *param_types = allocate<LLVMTypeRef>(param_count); | |
| 2183 | int gen_param_index = 0; | |
| 2184 | for (int param_decl_i = 0; param_decl_i < fn_proto->params.length; param_decl_i += 1) { | |
| 2185 | AstNode *param_node = fn_proto->params.at(param_decl_i); | |
| 2186 | assert(param_node->type == NodeTypeParamDecl); | |
| 2187 | if (is_param_decl_type_void(g, param_node)) | |
| 2188 | continue; | |
| 2189 | AstNode *type_node = param_node->data.param_decl.type; | |
| 2190 | param_types[gen_param_index] = fn_proto_type_from_type_node(g, type_node)->type_ref; | |
| 2191 | gen_param_index += 1; | |
| 2192 | } | |
| 2193 | LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, param_count, fn_proto->is_var_args); | |
| 2194 | ||
| 2195 | LLVMValueRef fn = LLVMAddFunction(g->module, buf_ptr(&fn_table_entry->symbol_name), function_type); | |
| 2196 | ||
| 2197 | for (int attr_i = 0; attr_i < fn_table_entry->fn_attr_list.length; attr_i += 1) { | |
| 2198 | FnAttrId attr_id = fn_table_entry->fn_attr_list.at(attr_i); | |
| 2199 | LLVMAddFunctionAttr(fn, to_llvm_fn_attr(attr_id)); | |
| 2200 | } | |
| 2201 | ||
| 2202 | LLVMSetLinkage(fn, fn_table_entry->internal_linkage ? LLVMInternalLinkage : LLVMExternalLinkage); | |
| 2203 | ||
| 2204 | if (type_is_unreachable(g, fn_proto->return_type)) { | |
| 2205 | LLVMAddFunctionAttr(fn, LLVMNoReturnAttribute); | |
| 2206 | } | |
| 2207 | LLVMSetFunctionCallConv(fn, fn_table_entry->calling_convention); | |
| 2208 | if (!fn_table_entry->is_extern) { | |
| 2209 | LLVMAddFunctionAttr(fn, LLVMNoUnwindAttribute); | |
| 2210 | } | |
| 2211 | ||
| 2212 | 2141 | // set parameter attributes |
| 2213 | gen_param_index = 0; | |
| 2142 | int gen_param_index = 0; | |
| 2214 | 2143 | for (int param_decl_i = 0; param_decl_i < fn_proto->params.length; param_decl_i += 1) { |
| 2215 | 2144 | AstNode *param_node = fn_proto->params.at(param_decl_i); |
| 2216 | 2145 | assert(param_node->type == NodeTypeParamDecl); |
| ... | ... | @@ -2218,7 +2147,7 @@ static void do_code_gen(CodeGen *g) { |
| 2218 | 2147 | continue; |
| 2219 | 2148 | AstNode *type_node = param_node->data.param_decl.type; |
| 2220 | 2149 | TypeTableEntry *param_type = fn_proto_type_from_type_node(g, type_node); |
| 2221 | LLVMValueRef argument_val = LLVMGetParam(fn, gen_param_index); | |
| 2150 | LLVMValueRef argument_val = LLVMGetParam(fn_table_entry->fn_value, gen_param_index); | |
| 2222 | 2151 | bool param_is_noalias = param_node->data.param_decl.is_noalias; |
| 2223 | 2152 | if (param_type->id == TypeTableEntryIdPointer && param_is_noalias) { |
| 2224 | 2153 | LLVMAddAttribute(argument_val, LLVMNoAliasAttribute); |
| ... | ... | @@ -2230,7 +2159,6 @@ static void do_code_gen(CodeGen *g) { |
| 2230 | 2159 | gen_param_index += 1; |
| 2231 | 2160 | } |
| 2232 | 2161 | |
| 2233 | fn_table_entry->fn_value = fn; | |
| 2234 | 2162 | } |
| 2235 | 2163 | |
| 2236 | 2164 | // Generate function definitions. |
| ... | ... | @@ -2245,22 +2173,9 @@ static void do_code_gen(CodeGen *g) { |
| 2245 | 2173 | assert(proto_node->type == NodeTypeFnProto); |
| 2246 | 2174 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; |
| 2247 | 2175 | |
| 2248 | // Add debug info. | |
| 2249 | unsigned line_number = fn_def_node->line + 1; | |
| 2250 | unsigned scope_line = line_number; | |
| 2251 | bool is_definition = true; | |
| 2252 | unsigned flags = 0; | |
| 2253 | bool is_optimized = g->build_type == CodeGenBuildTypeRelease; | |
| 2254 | LLVMZigDISubprogram *subprogram = LLVMZigCreateFunction(g->dbuilder, | |
| 2255 | import->block_context->di_scope, buf_ptr(&fn_table_entry->symbol_name), "", | |
| 2256 | import->di_file, line_number, | |
| 2257 | create_di_function_type(g, fn_proto, import->di_file), fn_table_entry->internal_linkage, | |
| 2258 | is_definition, scope_line, flags, is_optimized, fn); | |
| 2259 | ||
| 2260 | 2176 | LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn, "entry"); |
| 2261 | 2177 | LLVMPositionBuilderAtEnd(g->builder, entry_block); |
| 2262 | 2178 | |
| 2263 | fn_def_node->data.fn_def.block_context->di_scope = LLVMZigSubprogramToScope(subprogram); | |
| 2264 | 2179 | |
| 2265 | 2180 | AstNode *body_node = fn_def_node->data.fn_def.body; |
| 2266 | 2181 | build_label_blocks(g, body_node); |
src/zig_llvm.cpp+5| ... | ... | @@ -388,6 +388,11 @@ LLVMZigDIScope *LLVMZigSubprogramToScope(LLVMZigDISubprogram *subprogram) { |
| 388 | 388 | return reinterpret_cast<LLVMZigDIScope*>(scope); |
| 389 | 389 | } |
| 390 | 390 | |
| 391 | LLVMZigDIType *LLVMZigSubroutineToType(LLVMZigDISubroutineType *subrtype) { | |
| 392 | DIType *di_type = reinterpret_cast<DISubroutineType*>(subrtype); | |
| 393 | return reinterpret_cast<LLVMZigDIType*>(di_type); | |
| 394 | } | |
| 395 | ||
| 391 | 396 | LLVMZigDIScope *LLVMZigTypeToScope(LLVMZigDIType *type) { |
| 392 | 397 | DIScope *scope = reinterpret_cast<DIType*>(type); |
| 393 | 398 | return reinterpret_cast<LLVMZigDIScope*>(scope); |
src/zig_llvm.hpp+1| ... | ... | @@ -101,6 +101,7 @@ LLVMZigDIScope *LLVMZigCompileUnitToScope(LLVMZigDICompileUnit *compile_unit); |
| 101 | 101 | LLVMZigDIScope *LLVMZigFileToScope(LLVMZigDIFile *difile); |
| 102 | 102 | LLVMZigDIScope *LLVMZigSubprogramToScope(LLVMZigDISubprogram *subprogram); |
| 103 | 103 | LLVMZigDIScope *LLVMZigTypeToScope(LLVMZigDIType *type); |
| 104 | LLVMZigDIType *LLVMZigSubroutineToType(LLVMZigDISubroutineType *subrtype); | |
| 104 | 105 | |
| 105 | 106 | LLVMZigDILocalVariable *LLVMZigCreateLocalVariable(LLVMZigDIBuilder *dbuilder, unsigned tag, |
| 106 | 107 | LLVMZigDIScope *scope, const char *name, LLVMZigDIFile *file, unsigned line_no, |
test/run_tests.cpp-4| ... | ... | @@ -1296,10 +1296,6 @@ fn f() => { |
| 1296 | 1296 | fn f(a : unreachable) => {} |
| 1297 | 1297 | )SOURCE", 1, ".tmp_source.zig:2:10: error: parameter of type 'unreachable' not allowed"); |
| 1298 | 1298 | |
| 1299 | add_compile_fail_case("exporting a void parameter", R"SOURCE( | |
| 1300 | export fn f(a : void) => {} | |
| 1301 | )SOURCE", 1, ".tmp_source.zig:2:17: error: parameter of type 'void' not allowed on exported functions"); | |
| 1302 | ||
| 1303 | 1299 | add_compile_fail_case("unused label", R"SOURCE( |
| 1304 | 1300 | fn f() => { |
| 1305 | 1301 | a_label: |