| ... | ... | @@ -113,9 +113,30 @@ static AstNode *first_executing_node(AstNode *node) { |
| 113 | 113 | zig_unreachable(); |
| 114 | 114 | } |
| 115 | 115 | |
| 116 | | static void mark_impure_fn(BlockContext *context) { |
| 117 | | if (context->fn_entry) { |
| 118 | | context->fn_entry->is_pure = false; |
| 116 | static void mark_impure_fn(CodeGen *g, BlockContext *context, AstNode *node) { |
| 117 | if (!context->fn_entry) return; |
| 118 | if (!context->fn_entry->is_pure) return; |
| 119 | |
| 120 | context->fn_entry->is_pure = false; |
| 121 | if (context->fn_entry->want_pure == WantPureTrue) { |
| 122 | context->fn_entry->proto_node->data.fn_proto.skip = true; |
| 123 | |
| 124 | ErrorMsg *msg = add_node_error(g, context->fn_entry->proto_node, |
| 125 | buf_sprintf("failed to evaluate function at compile time")); |
| 126 | |
| 127 | add_error_note(g, msg, node, |
| 128 | buf_sprintf("unable to evaluate this expression at compile time")); |
| 129 | |
| 130 | if (context->fn_entry->want_pure_attr_node) { |
| 131 | add_error_note(g, msg, context->fn_entry->want_pure_attr_node, |
| 132 | buf_sprintf("required to be compile-time function here")); |
| 133 | } |
| 134 | |
| 135 | if (context->fn_entry->want_pure_return_type) { |
| 136 | add_error_note(g, msg, context->fn_entry->want_pure_return_type, |
| 137 | buf_sprintf("required to be compile-time function because of return type '%s'", |
| 138 | buf_ptr(&context->fn_entry->type_entry->data.fn.fn_type_id.return_type->name))); |
| 139 | } |
| 119 | 140 | } |
| 120 | 141 | } |
| 121 | 142 | |
| ... | ... | @@ -659,7 +680,7 @@ TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry * |
| 659 | 680 | } |
| 660 | 681 | |
| 661 | 682 | // accepts ownership of fn_type_id memory |
| 662 | | TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { |
| 683 | TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id, bool gen_debug_info) { |
| 663 | 684 | auto table_entry = g->fn_type_table.maybe_get(fn_type_id); |
| 664 | 685 | if (table_entry) { |
| 665 | 686 | return table_entry->value; |
| ... | ... | @@ -704,65 +725,67 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { |
| 704 | 725 | buf_appendf(&fn_type->name, " -> %s", buf_ptr(&fn_type_id->return_type->name)); |
| 705 | 726 | } |
| 706 | 727 | |
| 707 | | // next, loop over the parameters again and compute debug information |
| 708 | | // and codegen information |
| 709 | | bool first_arg_return = !fn_type_id->is_extern && handle_is_ptr(fn_type_id->return_type); |
| 710 | | // +1 for maybe making the first argument the return value |
| 711 | | LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(1 + fn_type_id->param_count); |
| 712 | | // +1 because 0 is the return type and +1 for maybe making first arg ret val |
| 713 | | LLVMZigDIType **param_di_types = allocate<LLVMZigDIType*>(2 + fn_type_id->param_count); |
| 714 | | param_di_types[0] = fn_type_id->return_type->di_type; |
| 715 | | int gen_param_index = 0; |
| 716 | | TypeTableEntry *gen_return_type; |
| 717 | | if (!type_has_bits(fn_type_id->return_type)) { |
| 718 | | gen_return_type = g->builtin_types.entry_void; |
| 719 | | } else if (first_arg_return) { |
| 720 | | TypeTableEntry *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false); |
| 721 | | gen_param_types[gen_param_index] = gen_type->type_ref; |
| 722 | | gen_param_index += 1; |
| 723 | | // after the gen_param_index += 1 because 0 is the return type |
| 724 | | param_di_types[gen_param_index] = gen_type->di_type; |
| 725 | | gen_return_type = g->builtin_types.entry_void; |
| 726 | | } else { |
| 727 | | gen_return_type = fn_type_id->return_type; |
| 728 | | } |
| 729 | | fn_type->data.fn.gen_return_type = gen_return_type; |
| 730 | | |
| 731 | | fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count); |
| 732 | | for (int i = 0; i < fn_type_id->param_count; i += 1) { |
| 733 | | FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i]; |
| 734 | | TypeTableEntry *type_entry = src_param_info->type; |
| 735 | | FnGenParamInfo *gen_param_info = &fn_type->data.fn.gen_param_info[i]; |
| 736 | | |
| 737 | | gen_param_info->src_index = i; |
| 738 | | gen_param_info->gen_index = -1; |
| 739 | | |
| 740 | | assert(type_is_complete(type_entry)); |
| 741 | | if (type_has_bits(type_entry)) { |
| 742 | | TypeTableEntry *gen_type; |
| 743 | | if (handle_is_ptr(type_entry)) { |
| 744 | | gen_type = get_pointer_to_type(g, type_entry, true); |
| 745 | | gen_param_info->is_byval = true; |
| 746 | | } else { |
| 747 | | gen_type = type_entry; |
| 748 | | } |
| 728 | if (gen_debug_info) { |
| 729 | // next, loop over the parameters again and compute debug information |
| 730 | // and codegen information |
| 731 | bool first_arg_return = !fn_type_id->is_extern && handle_is_ptr(fn_type_id->return_type); |
| 732 | // +1 for maybe making the first argument the return value |
| 733 | LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(1 + fn_type_id->param_count); |
| 734 | // +1 because 0 is the return type and +1 for maybe making first arg ret val |
| 735 | LLVMZigDIType **param_di_types = allocate<LLVMZigDIType*>(2 + fn_type_id->param_count); |
| 736 | param_di_types[0] = fn_type_id->return_type->di_type; |
| 737 | int gen_param_index = 0; |
| 738 | TypeTableEntry *gen_return_type; |
| 739 | if (!type_has_bits(fn_type_id->return_type)) { |
| 740 | gen_return_type = g->builtin_types.entry_void; |
| 741 | } else if (first_arg_return) { |
| 742 | TypeTableEntry *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false); |
| 749 | 743 | gen_param_types[gen_param_index] = gen_type->type_ref; |
| 750 | | gen_param_info->gen_index = gen_param_index; |
| 751 | | gen_param_info->type = gen_type; |
| 752 | | |
| 753 | 744 | gen_param_index += 1; |
| 754 | | |
| 755 | 745 | // after the gen_param_index += 1 because 0 is the return type |
| 756 | 746 | param_di_types[gen_param_index] = gen_type->di_type; |
| 747 | gen_return_type = g->builtin_types.entry_void; |
| 748 | } else { |
| 749 | gen_return_type = fn_type_id->return_type; |
| 757 | 750 | } |
| 758 | | } |
| 751 | fn_type->data.fn.gen_return_type = gen_return_type; |
| 752 | |
| 753 | fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count); |
| 754 | for (int i = 0; i < fn_type_id->param_count; i += 1) { |
| 755 | FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i]; |
| 756 | TypeTableEntry *type_entry = src_param_info->type; |
| 757 | FnGenParamInfo *gen_param_info = &fn_type->data.fn.gen_param_info[i]; |
| 758 | |
| 759 | gen_param_info->src_index = i; |
| 760 | gen_param_info->gen_index = -1; |
| 761 | |
| 762 | assert(type_is_complete(type_entry)); |
| 763 | if (type_has_bits(type_entry)) { |
| 764 | TypeTableEntry *gen_type; |
| 765 | if (handle_is_ptr(type_entry)) { |
| 766 | gen_type = get_pointer_to_type(g, type_entry, true); |
| 767 | gen_param_info->is_byval = true; |
| 768 | } else { |
| 769 | gen_type = type_entry; |
| 770 | } |
| 771 | gen_param_types[gen_param_index] = gen_type->type_ref; |
| 772 | gen_param_info->gen_index = gen_param_index; |
| 773 | gen_param_info->type = gen_type; |
| 774 | |
| 775 | gen_param_index += 1; |
| 759 | 776 | |
| 760 | | fn_type->data.fn.gen_param_count = gen_param_index; |
| 777 | // after the gen_param_index += 1 because 0 is the return type |
| 778 | param_di_types[gen_param_index] = gen_type->di_type; |
| 779 | } |
| 780 | } |
| 761 | 781 | |
| 762 | | fn_type->data.fn.raw_type_ref = LLVMFunctionType(gen_return_type->type_ref, |
| 763 | | gen_param_types, gen_param_index, fn_type_id->is_var_args); |
| 764 | | fn_type->type_ref = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0); |
| 765 | | fn_type->di_type = LLVMZigCreateSubroutineType(g->dbuilder, param_di_types, gen_param_index + 1, 0); |
| 782 | fn_type->data.fn.gen_param_count = gen_param_index; |
| 783 | |
| 784 | fn_type->data.fn.raw_type_ref = LLVMFunctionType(gen_return_type->type_ref, |
| 785 | gen_param_types, gen_param_index, fn_type_id->is_var_args); |
| 786 | fn_type->type_ref = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0); |
| 787 | fn_type->di_type = LLVMZigCreateSubroutineType(g->dbuilder, param_di_types, gen_param_index + 1, 0); |
| 788 | } |
| 766 | 789 | |
| 767 | 790 | g->fn_type_table.put(&fn_type->data.fn.fn_type_id, fn_type); |
| 768 | 791 | |
| ... | ... | @@ -862,8 +885,15 @@ static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, B |
| 862 | 885 | return analyze_type_expr_pointer_only(g, import, context, node, false); |
| 863 | 886 | } |
| 864 | 887 | |
| 888 | static bool fn_wants_full_static_eval(FnTableEntry *fn_table_entry) { |
| 889 | assert(fn_table_entry); |
| 890 | AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto; |
| 891 | return fn_proto->inline_arg_count == fn_proto->params.length && fn_table_entry->want_pure == WantPureTrue; |
| 892 | } |
| 893 | |
| 894 | // fn_table_entry is populated if and only if there is a function definition for this prototype |
| 865 | 895 | static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 866 | | TypeTableEntry *expected_type, AstNode *node, bool is_naked, bool is_cold) |
| 896 | TypeTableEntry *expected_type, AstNode *node, bool is_naked, bool is_cold, FnTableEntry *fn_table_entry) |
| 867 | 897 | { |
| 868 | 898 | assert(node->type == NodeTypeFnProto); |
| 869 | 899 | AstNodeFnProto *fn_proto = &node->data.fn_proto; |
| ... | ... | @@ -876,7 +906,6 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor |
| 876 | 906 | fn_type_id.is_extern = fn_proto->is_extern || (fn_proto->top_level_decl.visib_mod == VisibModExport); |
| 877 | 907 | fn_type_id.is_naked = is_naked; |
| 878 | 908 | fn_type_id.is_cold = is_cold; |
| 879 | | fn_type_id.is_inline = fn_proto->is_inline; |
| 880 | 909 | fn_type_id.param_count = fn_proto->params.length; |
| 881 | 910 | |
| 882 | 911 | if (fn_type_id.param_count > fn_type_id_prealloc_param_info_count) { |
| ... | ... | @@ -902,14 +931,6 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor |
| 902 | 931 | buf_sprintf("return type '%s' not allowed", buf_ptr(&fn_type_id.return_type->name))); |
| 903 | 932 | break; |
| 904 | 933 | case TypeTableEntryIdMetaType: |
| 905 | | if (!fn_proto->is_inline) { |
| 906 | | fn_proto->skip = true; |
| 907 | | add_node_error(g, fn_proto->return_type, |
| 908 | | buf_sprintf("function with return type '%s' must be declared inline", |
| 909 | | buf_ptr(&fn_type_id.return_type->name))); |
| 910 | | return g->builtin_types.entry_invalid; |
| 911 | | } |
| 912 | | break; |
| 913 | 934 | case TypeTableEntryIdUnreachable: |
| 914 | 935 | case TypeTableEntryIdVoid: |
| 915 | 936 | case TypeTableEntryIdBool: |
| ... | ... | @@ -984,7 +1005,33 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor |
| 984 | 1005 | return g->builtin_types.entry_invalid; |
| 985 | 1006 | } |
| 986 | 1007 | |
| 987 | | return get_fn_type(g, &fn_type_id); |
| 1008 | if (fn_table_entry && fn_type_id.return_type->id == TypeTableEntryIdMetaType) { |
| 1009 | fn_table_entry->want_pure = WantPureTrue; |
| 1010 | fn_table_entry->want_pure_return_type = fn_proto->return_type; |
| 1011 | |
| 1012 | ErrorMsg *err_msg = nullptr; |
| 1013 | for (int i = 0; i < fn_proto->params.length; i += 1) { |
| 1014 | AstNode *param_decl_node = fn_proto->params.at(i); |
| 1015 | assert(param_decl_node->type == NodeTypeParamDecl); |
| 1016 | if (!param_decl_node->data.param_decl.is_inline) { |
| 1017 | if (!err_msg) { |
| 1018 | err_msg = add_node_error(g, fn_proto->return_type, |
| 1019 | buf_sprintf("function with return type '%s' must declare all parameters inline", |
| 1020 | buf_ptr(&fn_type_id.return_type->name))); |
| 1021 | } |
| 1022 | add_error_note(g, err_msg, param_decl_node, |
| 1023 | buf_sprintf("non-inline parameter here")); |
| 1024 | } |
| 1025 | } |
| 1026 | if (err_msg) { |
| 1027 | fn_proto->skip = true; |
| 1028 | return g->builtin_types.entry_invalid; |
| 1029 | } |
| 1030 | } |
| 1031 | |
| 1032 | |
| 1033 | bool gen_debug_info = !(fn_table_entry && fn_wants_full_static_eval(fn_table_entry)); |
| 1034 | return get_fn_type(g, &fn_type_id, gen_debug_info); |
| 988 | 1035 | } |
| 989 | 1036 | |
| 990 | 1037 | static Buf *resolve_const_expr_str(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode **node) { |
| ... | ... | @@ -1110,10 +1157,12 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 1110 | 1157 | bool enable; |
| 1111 | 1158 | bool ok = resolve_const_expr_bool(g, import, import->block_context, |
| 1112 | 1159 | &directive_node->data.directive.expr, &enable); |
| 1113 | | if (!enable || !ok) { |
| 1160 | if (!ok || !enable) { |
| 1114 | 1161 | fn_table_entry->want_pure = WantPureFalse; |
| 1162 | } else if (ok && enable) { |
| 1163 | fn_table_entry->want_pure = WantPureTrue; |
| 1164 | fn_table_entry->want_pure_attr_node = directive_node->data.directive.expr; |
| 1115 | 1165 | } |
| 1116 | | // TODO cause compile error if enable is true and impure fn |
| 1117 | 1166 | } |
| 1118 | 1167 | } else { |
| 1119 | 1168 | add_node_error(g, directive_node, |
| ... | ... | @@ -1129,21 +1178,24 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 1129 | 1178 | |
| 1130 | 1179 | |
| 1131 | 1180 | TypeTableEntry *fn_type = analyze_fn_proto_type(g, import, containing_context, nullptr, node, |
| 1132 | | is_naked, is_cold); |
| 1181 | is_naked, is_cold, fn_table_entry); |
| 1133 | 1182 | |
| 1134 | 1183 | fn_table_entry->type_entry = fn_type; |
| 1135 | 1184 | fn_table_entry->is_test = is_test; |
| 1136 | | fn_table_entry->is_noinline = is_noinline; |
| 1137 | 1185 | |
| 1138 | 1186 | if (fn_type->id == TypeTableEntryIdInvalid) { |
| 1139 | 1187 | fn_proto->skip = true; |
| 1140 | 1188 | return; |
| 1141 | 1189 | } |
| 1142 | 1190 | |
| 1143 | | if (fn_proto->is_inline && fn_table_entry->is_noinline) { |
| 1191 | if (fn_proto->is_inline && is_noinline) { |
| 1144 | 1192 | add_node_error(g, node, buf_sprintf("function is both inline and noinline")); |
| 1145 | 1193 | fn_proto->skip = true; |
| 1146 | 1194 | return; |
| 1195 | } else if (fn_proto->is_inline) { |
| 1196 | fn_table_entry->fn_inline = FnInlineAlways; |
| 1197 | } else if (is_noinline) { |
| 1198 | fn_table_entry->fn_inline = FnInlineNever; |
| 1147 | 1199 | } |
| 1148 | 1200 | |
| 1149 | 1201 | |
| ... | ... | @@ -1159,48 +1211,54 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 1159 | 1211 | fn_table_entry->fn_def_node->data.fn_def.block_context = context; |
| 1160 | 1212 | } |
| 1161 | 1213 | |
| 1162 | | fn_table_entry->fn_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_type->data.fn.raw_type_ref); |
| 1163 | | |
| 1164 | | if (fn_proto->is_inline) { |
| 1165 | | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMAlwaysInlineAttribute); |
| 1166 | | } |
| 1167 | | if (fn_table_entry->is_noinline) { |
| 1168 | | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoInlineAttribute); |
| 1169 | | } |
| 1170 | | if (fn_type->data.fn.fn_type_id.is_naked) { |
| 1171 | | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNakedAttribute); |
| 1172 | | } |
| 1214 | if (!fn_wants_full_static_eval(fn_table_entry)) { |
| 1215 | fn_table_entry->fn_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_type->data.fn.raw_type_ref); |
| 1173 | 1216 | |
| 1174 | | LLVMSetLinkage(fn_table_entry->fn_value, fn_table_entry->internal_linkage ? |
| 1175 | | LLVMInternalLinkage : LLVMExternalLinkage); |
| 1217 | switch (fn_table_entry->fn_inline) { |
| 1218 | case FnInlineAlways: |
| 1219 | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMAlwaysInlineAttribute); |
| 1220 | break; |
| 1221 | case FnInlineNever: |
| 1222 | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoInlineAttribute); |
| 1223 | break; |
| 1224 | case FnInlineAuto: |
| 1225 | break; |
| 1226 | } |
| 1227 | if (fn_type->data.fn.fn_type_id.is_naked) { |
| 1228 | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNakedAttribute); |
| 1229 | } |
| 1176 | 1230 | |
| 1177 | | if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdUnreachable) { |
| 1178 | | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoReturnAttribute); |
| 1179 | | } |
| 1180 | | LLVMSetFunctionCallConv(fn_table_entry->fn_value, fn_type->data.fn.calling_convention); |
| 1181 | | if (!fn_table_entry->is_extern) { |
| 1182 | | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoUnwindAttribute); |
| 1183 | | } |
| 1184 | | if (!g->is_release_build && !fn_proto->is_inline) { |
| 1185 | | ZigLLVMAddFunctionAttr(fn_table_entry->fn_value, "no-frame-pointer-elim", "true"); |
| 1186 | | ZigLLVMAddFunctionAttr(fn_table_entry->fn_value, "no-frame-pointer-elim-non-leaf", nullptr); |
| 1187 | | } |
| 1231 | LLVMSetLinkage(fn_table_entry->fn_value, fn_table_entry->internal_linkage ? |
| 1232 | LLVMInternalLinkage : LLVMExternalLinkage); |
| 1188 | 1233 | |
| 1189 | | if (fn_table_entry->fn_def_node) { |
| 1190 | | // Add debug info. |
| 1191 | | unsigned line_number = node->line + 1; |
| 1192 | | unsigned scope_line = line_number; |
| 1193 | | bool is_definition = fn_table_entry->fn_def_node != nullptr; |
| 1194 | | unsigned flags = 0; |
| 1195 | | bool is_optimized = g->is_release_build; |
| 1196 | | LLVMZigDISubprogram *subprogram = LLVMZigCreateFunction(g->dbuilder, |
| 1197 | | containing_context->di_scope, buf_ptr(&fn_table_entry->symbol_name), "", |
| 1198 | | import->di_file, line_number, |
| 1199 | | fn_type->di_type, fn_table_entry->internal_linkage, |
| 1200 | | is_definition, scope_line, flags, is_optimized, nullptr); |
| 1234 | if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdUnreachable) { |
| 1235 | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoReturnAttribute); |
| 1236 | } |
| 1237 | LLVMSetFunctionCallConv(fn_table_entry->fn_value, fn_type->data.fn.calling_convention); |
| 1238 | if (!fn_table_entry->is_extern) { |
| 1239 | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoUnwindAttribute); |
| 1240 | } |
| 1241 | if (!g->is_release_build && !fn_proto->is_inline) { |
| 1242 | ZigLLVMAddFunctionAttr(fn_table_entry->fn_value, "no-frame-pointer-elim", "true"); |
| 1243 | ZigLLVMAddFunctionAttr(fn_table_entry->fn_value, "no-frame-pointer-elim-non-leaf", nullptr); |
| 1244 | } |
| 1201 | 1245 | |
| 1202 | | fn_table_entry->fn_def_node->data.fn_def.block_context->di_scope = LLVMZigSubprogramToScope(subprogram); |
| 1203 | | ZigLLVMFnSetSubprogram(fn_table_entry->fn_value, subprogram); |
| 1246 | if (fn_table_entry->fn_def_node) { |
| 1247 | // Add debug info. |
| 1248 | unsigned line_number = node->line + 1; |
| 1249 | unsigned scope_line = line_number; |
| 1250 | bool is_definition = fn_table_entry->fn_def_node != nullptr; |
| 1251 | unsigned flags = 0; |
| 1252 | bool is_optimized = g->is_release_build; |
| 1253 | LLVMZigDISubprogram *subprogram = LLVMZigCreateFunction(g->dbuilder, |
| 1254 | containing_context->di_scope, buf_ptr(&fn_table_entry->symbol_name), "", |
| 1255 | import->di_file, line_number, |
| 1256 | fn_type->di_type, fn_table_entry->internal_linkage, |
| 1257 | is_definition, scope_line, flags, is_optimized, nullptr); |
| 1258 | |
| 1259 | fn_table_entry->fn_def_node->data.fn_def.block_context->di_scope = LLVMZigSubprogramToScope(subprogram); |
| 1260 | ZigLLVMFnSetSubprogram(fn_table_entry->fn_value, subprogram); |
| 1261 | } |
| 1204 | 1262 | } |
| 1205 | 1263 | } |
| 1206 | 1264 | |
| ... | ... | @@ -1609,29 +1667,31 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN |
| 1609 | 1667 | |
| 1610 | 1668 | |
| 1611 | 1669 | } else { |
| 1612 | | g->fn_protos.append(fn_table_entry); |
| 1670 | resolve_function_proto(g, proto_node, fn_table_entry, import, containing_context); |
| 1613 | 1671 | |
| 1614 | | if (fn_def_node) { |
| 1615 | | g->fn_defs.append(fn_table_entry); |
| 1616 | | } |
| 1672 | if (!fn_wants_full_static_eval(fn_table_entry)) { |
| 1673 | g->fn_protos.append(fn_table_entry); |
| 1617 | 1674 | |
| 1618 | | bool is_main_fn = !is_generic_instance && |
| 1619 | | !parent_decl && (import == g->root_import) && |
| 1620 | | buf_eql_str(proto_name, "main"); |
| 1621 | | if (is_main_fn) { |
| 1622 | | g->main_fn = fn_table_entry; |
| 1623 | | } |
| 1675 | if (fn_def_node) { |
| 1676 | g->fn_defs.append(fn_table_entry); |
| 1677 | } |
| 1624 | 1678 | |
| 1625 | | resolve_function_proto(g, proto_node, fn_table_entry, import, containing_context); |
| 1679 | bool is_main_fn = !is_generic_instance && |
| 1680 | !parent_decl && (import == g->root_import) && |
| 1681 | buf_eql_str(proto_name, "main"); |
| 1682 | if (is_main_fn) { |
| 1683 | g->main_fn = fn_table_entry; |
| 1684 | } |
| 1626 | 1685 | |
| 1627 | | if (is_main_fn && !g->link_libc) { |
| 1628 | | TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void); |
| 1629 | | TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type; |
| 1630 | | if (actual_return_type != err_void) { |
| 1631 | | AstNode *return_type_node = fn_table_entry->proto_node->data.fn_proto.return_type; |
| 1632 | | add_node_error(g, return_type_node, |
| 1633 | | buf_sprintf("expected return type of main to be '%%void', instead is '%s'", |
| 1634 | | buf_ptr(&actual_return_type->name))); |
| 1686 | if (is_main_fn && !g->link_libc) { |
| 1687 | TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void); |
| 1688 | TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type; |
| 1689 | if (actual_return_type != err_void) { |
| 1690 | AstNode *return_type_node = fn_table_entry->proto_node->data.fn_proto.return_type; |
| 1691 | add_node_error(g, return_type_node, |
| 1692 | buf_sprintf("expected return type of main to be '%%void', instead is '%s'", |
| 1693 | buf_ptr(&actual_return_type->name))); |
| 1694 | } |
| 1635 | 1695 | } |
| 1636 | 1696 | } |
| 1637 | 1697 | } |
| ... | ... | @@ -3022,7 +3082,7 @@ static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, Variabl |
| 3022 | 3082 | { |
| 3023 | 3083 | get_resolved_expr(source_node)->variable = var; |
| 3024 | 3084 | if (!var_is_pure(var, context)) { |
| 3025 | | mark_impure_fn(context); |
| 3085 | mark_impure_fn(g, context, source_node); |
| 3026 | 3086 | } |
| 3027 | 3087 | if (var->is_const && var->val_node) { |
| 3028 | 3088 | ConstExprValue *other_const_val = &get_resolved_expr(var->val_node)->const_val; |
| ... | ... | @@ -3102,7 +3162,7 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, |
| 3102 | 3162 | return g->builtin_types.entry_invalid; |
| 3103 | 3163 | } |
| 3104 | 3164 | |
| 3105 | | mark_impure_fn(context); |
| 3165 | mark_impure_fn(g, context, node); |
| 3106 | 3166 | add_node_error(g, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); |
| 3107 | 3167 | return g->builtin_types.entry_invalid; |
| 3108 | 3168 | } |
| ... | ... | @@ -3943,7 +4003,8 @@ static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, |
| 3943 | 4003 | static TypeTableEntry *analyze_fn_proto_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 3944 | 4004 | TypeTableEntry *expected_type, AstNode *node) |
| 3945 | 4005 | { |
| 3946 | | TypeTableEntry *type_entry = analyze_fn_proto_type(g, import, context, expected_type, node, false, false); |
| 4006 | TypeTableEntry *type_entry = analyze_fn_proto_type(g, import, context, expected_type, node, |
| 4007 | false, false, nullptr); |
| 3947 | 4008 | |
| 3948 | 4009 | if (type_entry->id == TypeTableEntryIdInvalid) { |
| 3949 | 4010 | return type_entry; |
| ... | ... | @@ -4386,7 +4447,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B |
| 4386 | 4447 | (wanted_type->data.structure.fields[0].type_entry->data.pointer.is_const || |
| 4387 | 4448 | !actual_type->data.structure.fields[0].type_entry->data.pointer.is_const)) |
| 4388 | 4449 | { |
| 4389 | | mark_impure_fn(context); |
| 4450 | mark_impure_fn(g, context, node); |
| 4390 | 4451 | return resolve_cast(g, context, node, expr_node, wanted_type, CastOpResizeSlice, true); |
| 4391 | 4452 | } |
| 4392 | 4453 | |
| ... | ... | @@ -4395,7 +4456,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B |
| 4395 | 4456 | actual_type->id == TypeTableEntryIdArray && |
| 4396 | 4457 | is_u8(actual_type->data.array.child_type)) |
| 4397 | 4458 | { |
| 4398 | | mark_impure_fn(context); |
| 4459 | mark_impure_fn(g, context, node); |
| 4399 | 4460 | uint64_t child_type_size = type_size(g, |
| 4400 | 4461 | wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type); |
| 4401 | 4462 | if (actual_type->data.array.len % child_type_size == 0) { |
| ... | ... | @@ -5276,11 +5337,11 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry |
| 5276 | 5337 | case BuiltinFnIdErrName: |
| 5277 | 5338 | return analyze_err_name(g, import, context, node); |
| 5278 | 5339 | case BuiltinFnIdBreakpoint: |
| 5279 | | mark_impure_fn(context); |
| 5340 | mark_impure_fn(g, context, node); |
| 5280 | 5341 | return g->builtin_types.entry_void; |
| 5281 | 5342 | case BuiltinFnIdReturnAddress: |
| 5282 | 5343 | case BuiltinFnIdFrameAddress: |
| 5283 | | mark_impure_fn(context); |
| 5344 | mark_impure_fn(g, context, node); |
| 5284 | 5345 | return builtin_fn->return_type; |
| 5285 | 5346 | case BuiltinFnIdEmbedFile: |
| 5286 | 5347 | return analyze_embed_file(g, import, context, node); |
| ... | ... | @@ -5388,6 +5449,9 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, |
| 5388 | 5449 | if (ok_invocation && fn_table_entry && fn_table_entry->is_pure && fn_table_entry->want_pure != WantPureFalse) { |
| 5389 | 5450 | if (fn_table_entry->anal_state == FnAnalStateReady) { |
| 5390 | 5451 | analyze_fn_body(g, fn_table_entry); |
| 5452 | if (fn_table_entry->proto_node->data.fn_proto.skip) { |
| 5453 | return g->builtin_types.entry_invalid; |
| 5454 | } |
| 5391 | 5455 | } |
| 5392 | 5456 | if (all_args_const_expr) { |
| 5393 | 5457 | if (fn_table_entry->is_pure && fn_table_entry->anal_state == FnAnalStateComplete) { |
| ... | ... | @@ -5401,7 +5465,10 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, |
| 5401 | 5465 | } |
| 5402 | 5466 | if (!ok_invocation || !fn_table_entry || !fn_table_entry->is_pure || fn_table_entry->want_pure == WantPureFalse) { |
| 5403 | 5467 | // calling an impure fn is impure |
| 5404 | | mark_impure_fn(context); |
| 5468 | mark_impure_fn(g, context, node); |
| 5469 | if (fn_table_entry && fn_table_entry->want_pure == WantPureTrue) { |
| 5470 | return g->builtin_types.entry_invalid; |
| 5471 | } |
| 5405 | 5472 | } |
| 5406 | 5473 | |
| 5407 | 5474 | if (handle_is_ptr(return_type)) { |
| ... | ... | @@ -6298,7 +6365,7 @@ static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, |
| 6298 | 6365 | static TypeTableEntry *analyze_asm_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 6299 | 6366 | TypeTableEntry *expected_type, AstNode *node) |
| 6300 | 6367 | { |
| 6301 | | mark_impure_fn(context); |
| 6368 | mark_impure_fn(g, context, node); |
| 6302 | 6369 | |
| 6303 | 6370 | node->data.asm_expr.return_count = 0; |
| 6304 | 6371 | TypeTableEntry *return_type = g->builtin_types.entry_void; |