| ... | ... | @@ -1061,13 +1061,31 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_cou |
| 1061 | 1061 | fn_type_id->is_var_args = fn_proto->is_var_args; |
| 1062 | 1062 | } |
| 1063 | 1063 | |
| 1064 | | static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope, uint32_t alignment) { |
| 1064 | static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_t *result) { |
| 1065 | IrInstruction *align_result = analyze_const_value(g, scope, node, get_align_amt_type(g), nullptr); |
| 1066 | if (type_is_invalid(align_result->value.type)) |
| 1067 | return false; |
| 1068 | |
| 1069 | uint32_t align_bytes = bigint_as_unsigned(&align_result->value.data.x_bigint); |
| 1070 | if (align_bytes == 0) { |
| 1071 | add_node_error(g, node, buf_sprintf("alignment must be >= 1")); |
| 1072 | return false; |
| 1073 | } |
| 1074 | if (!is_power_of_2(align_bytes)) { |
| 1075 | add_node_error(g, node, buf_sprintf("alignment value %" PRIu32 " is not a power of 2", align_bytes)); |
| 1076 | return false; |
| 1077 | } |
| 1078 | |
| 1079 | *result = align_bytes; |
| 1080 | return true; |
| 1081 | } |
| 1082 | |
| 1083 | static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope) { |
| 1065 | 1084 | assert(proto_node->type == NodeTypeFnProto); |
| 1066 | 1085 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; |
| 1067 | 1086 | |
| 1068 | 1087 | FnTypeId fn_type_id = {0}; |
| 1069 | 1088 | init_fn_type_id(&fn_type_id, proto_node, proto_node->data.fn_proto.params.length); |
| 1070 | | fn_type_id.alignment = alignment; |
| 1071 | 1089 | |
| 1072 | 1090 | for (; fn_type_id.next_param_index < fn_type_id.param_count; fn_type_id.next_param_index += 1) { |
| 1073 | 1091 | AstNode *param_node = fn_proto->params.at(fn_type_id.next_param_index); |
| ... | ... | @@ -1156,6 +1174,12 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c |
| 1156 | 1174 | param_info->is_noalias = param_node->data.param_decl.is_noalias; |
| 1157 | 1175 | } |
| 1158 | 1176 | |
| 1177 | if (fn_proto->align_expr != nullptr) { |
| 1178 | if (!analyze_const_align(g, child_scope, fn_proto->align_expr, &fn_type_id.alignment)) { |
| 1179 | return g->builtin_types.entry_invalid; |
| 1180 | } |
| 1181 | } |
| 1182 | |
| 1159 | 1183 | fn_type_id.return_type = analyze_type_expr(g, child_scope, fn_proto->return_type); |
| 1160 | 1184 | |
| 1161 | 1185 | switch (fn_type_id.return_type->id) { |
| ... | ... | @@ -2012,25 +2036,6 @@ TypeTableEntry *get_test_fn_type(CodeGen *g) { |
| 2012 | 2036 | return g->test_fn_type; |
| 2013 | 2037 | } |
| 2014 | 2038 | |
| 2015 | | static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_t *result) { |
| 2016 | | IrInstruction *align_result = analyze_const_value(g, scope, node, get_align_amt_type(g), nullptr); |
| 2017 | | if (type_is_invalid(align_result->value.type)) |
| 2018 | | return false; |
| 2019 | | |
| 2020 | | uint32_t align_bytes = bigint_as_unsigned(&align_result->value.data.x_bigint); |
| 2021 | | if (align_bytes == 0) { |
| 2022 | | add_node_error(g, node, buf_sprintf("alignment must be >= 1")); |
| 2023 | | return false; |
| 2024 | | } |
| 2025 | | if (!is_power_of_2(align_bytes)) { |
| 2026 | | add_node_error(g, node, buf_sprintf("alignment value %" PRIu32 " is not a power of 2", align_bytes)); |
| 2027 | | return false; |
| 2028 | | } |
| 2029 | | |
| 2030 | | *result = align_bytes; |
| 2031 | | return true; |
| 2032 | | } |
| 2033 | | |
| 2034 | 2039 | static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { |
| 2035 | 2040 | ImportTableEntry *import = tld_fn->base.import; |
| 2036 | 2041 | AstNode *source_node = tld_fn->base.source_node; |
| ... | ... | @@ -2061,16 +2066,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { |
| 2061 | 2066 | |
| 2062 | 2067 | Scope *child_scope = fn_table_entry->fndef_scope ? &fn_table_entry->fndef_scope->base : tld_fn->base.parent_scope; |
| 2063 | 2068 | |
| 2064 | | uint32_t alignment = 0; |
| 2065 | | if (fn_proto->align_expr != nullptr) { |
| 2066 | | if (!analyze_const_align(g, child_scope, fn_proto->align_expr, &alignment)) { |
| 2067 | | fn_table_entry->type_entry = g->builtin_types.entry_invalid; |
| 2068 | | tld_fn->base.resolution = TldResolutionInvalid; |
| 2069 | | return; |
| 2070 | | } |
| 2071 | | } |
| 2072 | | |
| 2073 | | fn_table_entry->type_entry = analyze_fn_type(g, source_node, child_scope, alignment); |
| 2069 | fn_table_entry->type_entry = analyze_fn_type(g, source_node, child_scope); |
| 2074 | 2070 | |
| 2075 | 2071 | if (fn_table_entry->type_entry->id == TypeTableEntryIdInvalid) { |
| 2076 | 2072 | tld_fn->base.resolution = TldResolutionInvalid; |