diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index 8390442ae..27d4d2c8a 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -120,12 +120,18 @@ enum BuiltinProcId { BuiltinProc_offset_of, BuiltinProc_offset_of_val, BuiltinProc_static_assert, + BuiltinProc_len, BuiltinProc_cap, BuiltinProc_copy, BuiltinProc_append, + BuiltinProc_swizzle, + BuiltinProc_ptr_offset, + BuiltinProc_ptr_sub, + BuiltinProc_slice_ptr, + BuiltinProc_Count, }; struct BuiltinProc { @@ -151,6 +157,10 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = { {STR_LIT("append"), 2, false, Expression_Expression}, {STR_LIT("swizzle"), 1, true, Expression_Expression}, + + {STR_LIT("ptr_offset"), 2, false, Expression_Expression}, + {STR_LIT("ptr_sub"), 2, false, Expression_Expression}, + {STR_LIT("slice_ptr"), 2, true, Expression_Expression}, }; struct CheckerContext { diff --git a/src/checker/entity.cpp b/src/checker/entity.cpp index 90c4f3198..339eda248 100644 --- a/src/checker/entity.cpp +++ b/src/checker/entity.cpp @@ -39,11 +39,13 @@ struct Entity { struct { ExactValue value; } Constant; struct { b8 visited; // Cycle detection - b8 is_field; // Is struct field b8 used; // Variable is used - b8 anonymous; // Variable is an anonymous struct field + b8 is_field; // Is struct field + b8 anonymous; // Variable is an anonymous } Variable; - struct { b8 used; } Procedure; + struct { + b8 used; + } Procedure; struct { BuiltinProcId id; } Builtin; }; }; diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index a3aa6eb10..8cf42c022 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -1,17 +1,124 @@ -void check_assignment (Checker *c, Operand *operand, Type *type, String context_name); -b32 check_is_assignable_to (Checker *c, Operand *operand, Type *type); -void check_expr (Checker *c, Operand *operand, AstNode *expression); -void check_multi_expr (Checker *c, Operand *operand, AstNode *expression); -void check_expr_or_type (Checker *c, Operand *operand, AstNode *expression); -ExpressionKind check_expr_base (Checker *c, Operand *operand, AstNode *expression, Type *type_hint = NULL); -Type * check_type (Checker *c, AstNode *expression, Type *named_type = NULL, CycleChecker *cycle_checker = NULL); -void check_selector (Checker *c, Operand *operand, AstNode *node); -void check_not_tuple (Checker *c, Operand *operand); -void convert_to_typed (Checker *c, Operand *operand, Type *target_type); -gbString expr_to_string (AstNode *expression); -void check_entity_decl (Checker *c, Entity *e, DeclInfo *decl, Type *named_type, CycleChecker *cycle_checker = NULL); -void check_proc_body (Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body); -void update_expr_type (Checker *c, AstNode *e, Type *type, b32 final); +void check_expr (Checker *c, Operand *operand, AstNode *expression); +void check_multi_expr (Checker *c, Operand *operand, AstNode *expression); +void check_expr_or_type (Checker *c, Operand *operand, AstNode *expression); +ExpressionKind check_expr_base (Checker *c, Operand *operand, AstNode *expression, Type *type_hint = NULL); +Type * check_type (Checker *c, AstNode *expression, Type *named_type = NULL, CycleChecker *cycle_checker = NULL); +void check_selector (Checker *c, Operand *operand, AstNode *node); +void check_not_tuple (Checker *c, Operand *operand); +b32 check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value); +void convert_to_typed (Checker *c, Operand *operand, Type *target_type); +gbString expr_to_string (AstNode *expression); +void check_entity_decl (Checker *c, Entity *e, DeclInfo *decl, Type *named_type, CycleChecker *cycle_checker = NULL); +void check_proc_body (Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body); +void update_expr_type (Checker *c, AstNode *e, Type *type, b32 final); + + + +b32 check_is_assignable_to_using_subtype(Checker *c, Type *dst, Type *src) { + return false; +} + +b32 check_is_assignable_to(Checker *c, Operand *operand, Type *type, b32 is_argument = false) { + if (operand->mode == Addressing_Invalid || + type == t_invalid) { + return true; + } + + Type *s = operand->type; + + if (are_types_identical(s, type)) + return true; + + Type *src = get_base_type(s); + Type *dst = get_base_type(type); + + if (is_type_untyped(src)) { + switch (dst->kind) { + case Type_Basic: + if (operand->mode == Addressing_Constant) + return check_value_is_expressible(c, operand->value, dst, NULL); + if (src->kind == Type_Basic) + return src->Basic.kind == Basic_UntypedBool && is_type_boolean(dst); + break; + case Type_Pointer: + return src->Basic.kind == Basic_UntypedPointer; + } + } + + if (are_types_identical(dst, src) && (!is_type_named(dst) || !is_type_named(src))) + return true; + + if (is_type_pointer(dst) && is_type_rawptr(src)) + return true; + + if (is_type_rawptr(dst) && is_type_pointer(src)) + return true; + + if (dst->kind == Type_Array && src->kind == Type_Array) { + if (are_types_identical(dst->Array.elem, src->Array.elem)) { + return dst->Array.count == src->Array.count; + } + } + + if (dst->kind == Type_Slice && src->kind == Type_Slice) { + if (are_types_identical(dst->Slice.elem, src->Slice.elem)) { + return true; + } + } + + if (is_argument) { + // Polymorphism for subtyping + if (check_is_assignable_to_using_subtype(c, dst, src)) { + return true; + } + } + + + return false; + +} + + +// NOTE(bill): `content_name` is for debugging +// TODO(bill): Maybe allow assignment to tuples? +void check_assignment(Checker *c, Operand *operand, Type *type, String context_name, b32 is_argument = false) { + check_not_tuple(c, operand); + if (operand->mode == Addressing_Invalid) + return; + + if (is_type_untyped(operand->type)) { + Type *target_type = type; + + if (type == NULL) + target_type = default_type(operand->type); + convert_to_typed(c, operand, target_type); + if (operand->mode == Addressing_Invalid) + return; + } + + if (type != NULL) { + if (!check_is_assignable_to(c, operand, type, is_argument)) { + gbString type_string = type_to_string(type); + gbString op_type_string = type_to_string(operand->type); + gbString expr_str = expr_to_string(operand->expr); + defer (gb_string_free(type_string)); + defer (gb_string_free(op_type_string)); + defer (gb_string_free(expr_str)); + + + // TODO(bill): is this a good enough error message? + error(&c->error_collector, ast_node_token(operand->expr), + "Cannot assign value `%s` of type `%s` to `%s` in %.*s", + expr_str, + op_type_string, + type_string, + LIT(context_name)); + + operand->mode = Addressing_Invalid; + } + } +} + void populate_using_entity_map(Checker *c, AstNode *node, Type *t, Map *entity_map) { t = get_base_type(type_deref(t)); @@ -1095,7 +1202,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { if (!are_types_identical(x->type, y->type)) { if (x->type != t_invalid && - y->type != t_invalid) { + y->type != t_invalid) { gbString xt = type_to_string(x->type); gbString yt = type_to_string(y->type); defer (gb_string_free(xt)); @@ -1906,6 +2013,166 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) operand->type = make_type_vector(c->allocator, elem_type, arg_count); operand->mode = Addressing_Value; } break; + + case BuiltinProc_ptr_offset: { + // ptr_offset :: proc(ptr: ^T, offset: int) -> ^T + // ^T cannot be rawptr + Type *ptr_type = get_base_type(operand->type); + if (!is_type_pointer(ptr_type)) { + gbString type_str = type_to_string(operand->type); + defer (gb_string_free(type_str)); + error(&c->error_collector, ast_node_token(call), + "Expected a pointer to `ptr_offset`, got `%s`", + type_str); + return false; + } + + if (ptr_type == t_rawptr) { + error(&c->error_collector, ast_node_token(call), + "`rawptr` cannot have pointer arithmetic"); + return false; + } + + AstNode *offset = ce->arg_list->next; + Operand op = {}; + check_expr(c, &op, offset); + if (op.mode == Addressing_Invalid) + return false; + Type *offset_type = get_base_type(op.type); + if (!is_type_integer(offset_type)) { + error(&c->error_collector, ast_node_token(op.expr), "Pointer offsets for `ptr_offset` must be an integer"); + return false; + } + + if (operand->mode == Addressing_Constant && + op.mode == Addressing_Constant) { + u8 *ptr = cast(u8 *)operand->value.value_pointer; + isize elem_size = type_size_of(c->sizes, c->allocator, ptr_type->Pointer.elem); + ptr += elem_size * op.value.value_integer; + operand->value.value_pointer = ptr; + } else { + operand->mode = Addressing_Value; + } + + } break; + + case BuiltinProc_ptr_sub: { + // ptr_sub :: proc(a, b: ^T) -> int + // ^T cannot be rawptr + Type *ptr_type = get_base_type(operand->type); + if (!is_type_pointer(ptr_type)) { + gbString type_str = type_to_string(operand->type); + defer (gb_string_free(type_str)); + error(&c->error_collector, ast_node_token(call), + "Expected a pointer to `ptr_add`, got `%s`", + type_str); + return false; + } + + if (ptr_type == t_rawptr) { + error(&c->error_collector, ast_node_token(call), + "`rawptr` cannot have pointer arithmetic"); + return false; + } + AstNode *offset = ce->arg_list->next; + Operand op = {}; + check_expr(c, &op, offset); + if (op.mode == Addressing_Invalid) + return false; + if (!is_type_pointer(op.type)) { + gbString type_str = type_to_string(operand->type); + defer (gb_string_free(type_str)); + error(&c->error_collector, ast_node_token(call), + "Expected a pointer to `ptr_add`, got `%s`", + type_str); + return false; + } + + if (get_base_type(op.type) == t_rawptr) { + error(&c->error_collector, ast_node_token(call), + "`rawptr` cannot have pointer arithmetic"); + return false; + } + + if (!are_types_identical(operand->type, op.type)) { + gbString a = type_to_string(operand->type); + gbString b = type_to_string(op.type); + defer (gb_string_free(a)); + defer (gb_string_free(b)); + error(&c->error_collector, ast_node_token(op.expr), + "`ptr_sub` requires to pointer of the same type. Got `%s` and `%s`.", a, b); + return false; + } + + operand->type = t_int; + + if (operand->mode == Addressing_Constant && + op.mode == Addressing_Constant) { + u8 *ptr_a = cast(u8 *)operand->value.value_pointer; + u8 *ptr_b = cast(u8 *)op.value.value_pointer; + isize elem_size = type_size_of(c->sizes, c->allocator, ptr_type->Pointer.elem); + operand->value = make_exact_value_integer((ptr_a - ptr_b) / elem_size); + } else { + operand->mode = Addressing_Value; + } + } break; + + case BuiltinProc_slice_ptr: { + // slice_ptr :: proc(a: ^T, len: int[, cap: int]) -> []T + // ^T cannot be rawptr + Type *ptr_type = get_base_type(operand->type); + if (!is_type_pointer(ptr_type)) { + gbString type_str = type_to_string(operand->type); + defer (gb_string_free(type_str)); + error(&c->error_collector, ast_node_token(call), + "Expected a pointer to `ptr_add`, got `%s`", + type_str); + return false; + } + + if (ptr_type == t_rawptr) { + error(&c->error_collector, ast_node_token(call), + "`rawptr` cannot have pointer arithmetic"); + return false; + } + AstNode *len = ce->arg_list->next; + Operand op = {}; + check_expr(c, &op, len); + if (op.mode == Addressing_Invalid) + return false; + if (!is_type_integer(op.type)) { + gbString type_str = type_to_string(operand->type); + defer (gb_string_free(type_str)); + error(&c->error_collector, ast_node_token(call), + "Length for `slice_ptr` must be an integer, got `%s`", + type_str); + return false; + } + + AstNode *cap = len->next; + if (cap != NULL) { + check_expr(c, &op, len); + if (op.mode == Addressing_Invalid) + return false; + if (!is_type_integer(op.type)) { + gbString type_str = type_to_string(operand->type); + defer (gb_string_free(type_str)); + error(&c->error_collector, ast_node_token(call), + "Capacity for `slice_ptr` must be an integer, got `%s`", + type_str); + return false; + } + if (cap->next != NULL) { + error(&c->error_collector, ast_node_token(call), + "Too many arguments to `slice_ptr`, expected either 2 or 3"); + return false; + } + } + + operand->type = make_type_slice(c->allocator, ptr_type->Pointer.elem); + operand->mode = Addressing_Value; + } break; + } return true; @@ -1937,7 +2204,7 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode continue; if (operand->type->kind != Type_Tuple) { check_not_tuple(c, operand); - check_assignment(c, operand, sig_params[param_index]->type, make_string("argument")); + check_assignment(c, operand, sig_params[param_index]->type, make_string("argument"), true); param_index++; } else { auto *tuple = &operand->type->Tuple; @@ -1949,7 +2216,7 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode operand->type = e->type; operand->mode = Addressing_Value; check_not_tuple(c, operand); - check_assignment(c, operand, sig_params[param_index]->type, make_string("argument")); + check_assignment(c, operand, sig_params[param_index]->type, make_string("argument"), true); } if (i < tuple->variable_count && param_index == param_count) { @@ -2367,11 +2634,15 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ o->mode = Addressing_Variable; break; - case Type_Pointer: - valid = true; - o->mode = Addressing_Variable; - o->type = get_base_type(t->Pointer.elem); - break; + case Type_Pointer: { + Type *bt = get_base_type(t->Pointer.elem); + if (bt->kind == Type_Array) { + valid = true; + max_count = bt->Array.count; + o->mode = Addressing_Variable; + o->type = bt->Array.elem; + } + } break; } if (!valid) { @@ -2409,7 +2680,6 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ max_count = o->value.value_string.len; } o->type = t_string; - o->mode = Addressing_Value; } break; @@ -2423,19 +2693,20 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ goto error; } o->type = make_type_slice(c->allocator, t->Array.elem); - o->mode = Addressing_Value; break; case Type_Slice: valid = true; - o->mode = Addressing_Value; break; - case Type_Pointer: - valid = true; - o->type = make_type_slice(c->allocator, get_base_type(t->Pointer.elem)); - o->mode = Addressing_Value; - break; + case Type_Pointer: { + Type *bt = get_base_type(t->Pointer.elem); + if (bt->kind == Type_Array) { + valid = true; + max_count = bt->Array.count; + o->type = make_type_slice(c->allocator, bt->Array.elem); + } + } break; } if (!valid) { @@ -2445,6 +2716,8 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ goto error; } + o->mode = Addressing_Value; + i64 indices[3] = {}; AstNode *nodes[3] = {se->low, se->high, se->max}; for (isize i = 0; i < gb_count_of(nodes); i++) { diff --git a/src/checker/stmt.cpp b/src/checker/stmt.cpp index 7b9664595..31a824f5a 100644 --- a/src/checker/stmt.cpp +++ b/src/checker/stmt.cpp @@ -70,102 +70,6 @@ b32 check_is_terminating(Checker *c, AstNode *node) { return false; } - -b32 check_is_assignable_to(Checker *c, Operand *operand, Type *type) { - if (operand->mode == Addressing_Invalid || - type == t_invalid) { - return true; - } - - Type *s = operand->type; - - if (are_types_identical(s, type)) - return true; - - Type *sb = get_base_type(s); - Type *tb = get_base_type(type); - - if (is_type_untyped(sb)) { - switch (tb->kind) { - case Type_Basic: - if (operand->mode == Addressing_Constant) - return check_value_is_expressible(c, operand->value, tb, NULL); - if (sb->kind == Type_Basic) - return sb->Basic.kind == Basic_UntypedBool && is_type_boolean(tb); - break; - case Type_Pointer: - return sb->Basic.kind == Basic_UntypedPointer; - } - } - - if (are_types_identical(sb, tb) && (!is_type_named(sb) || !is_type_named(tb))) - return true; - - if (is_type_pointer(sb) && is_type_rawptr(tb)) - return true; - - if (is_type_rawptr(sb) && is_type_pointer(tb)) - return true; - - if (sb->kind == Type_Array && tb->kind == Type_Array) { - if (are_types_identical(sb->Array.elem, tb->Array.elem)) { - return sb->Array.count == tb->Array.count; - } - } - - if (sb->kind == Type_Slice && tb->kind == Type_Slice) { - if (are_types_identical(sb->Slice.elem, tb->Slice.elem)) { - return true; - } - } - - - return false; - -} - - -// NOTE(bill): `content_name` is for debugging -// TODO(bill): Maybe allow assignment to tuples? -void check_assignment(Checker *c, Operand *operand, Type *type, String context_name) { - check_not_tuple(c, operand); - if (operand->mode == Addressing_Invalid) - return; - - if (is_type_untyped(operand->type)) { - Type *target_type = type; - - if (type == NULL) - target_type = default_type(operand->type); - convert_to_typed(c, operand, target_type); - if (operand->mode == Addressing_Invalid) - return; - } - - if (type != NULL) { - if (!check_is_assignable_to(c, operand, type)) { - gbString type_string = type_to_string(type); - gbString op_type_string = type_to_string(operand->type); - gbString expr_str = expr_to_string(operand->expr); - defer (gb_string_free(type_string)); - defer (gb_string_free(op_type_string)); - defer (gb_string_free(expr_str)); - - - // TODO(bill): is this a good enough error message? - error(&c->error_collector, ast_node_token(operand->expr), - "Cannot assign value `%s` of type `%s` to `%s` in %.*s", - expr_str, - op_type_string, - type_string, - LIT(context_name)); - - operand->mode = Addressing_Invalid; - } - } -} - - Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) { if (op_a->mode == Addressing_Invalid || op_a->type == t_invalid) { diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index 6c5b8f51b..181fb8d5b 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -985,9 +985,9 @@ ssaValue *ssa_emit_arith(ssaProcedure *proc, Token op, ssaValue *left, ssaValue break; } - ssaValue *v = ssa_make_instr_binary_op(proc, op, left, right); + ssaValue *v = ssa_emit(proc, ssa_make_instr_binary_op(proc, op, left, right)); ssa_set_type(v, type); - return ssa_emit(proc, v); + return v; } ssaValue *ssa_emit_comp(ssaProcedure *proc, Token op, ssaValue *left, ssaValue *right) { @@ -1696,18 +1696,23 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue // copy :: proc(dst, src: []Type) -> int AstNode *dst_node = ce->arg_list; AstNode *src_node = ce->arg_list->next; - ssaValue *dst_slice = ssa_build_addr(proc, dst_node).addr; - ssaValue *src_slice = ssa_build_addr(proc, src_node).addr; + ssaValue *dst_slice = ssa_build_expr(proc, dst_node); + ssaValue *src_slice = ssa_build_expr(proc, src_node); Type *slice_type = get_base_type(ssa_type(dst_slice)); GB_ASSERT(slice_type->kind == Type_Slice); Type *elem_type = slice_type->Slice.elem; i64 size_of_elem = type_size_of(proc->module->sizes, proc->module->allocator, elem_type); - ssaValue *dst = ssa_emit_conv(proc, ssa_slice_elem(proc, dst_slice), t_rawptr); - ssaValue *src = ssa_emit_conv(proc, ssa_slice_elem(proc, src_slice), t_rawptr); + ssaValue *d = ssa_add_local_generated(proc, slice_type); + ssaValue *s = ssa_add_local_generated(proc, slice_type); + ssa_emit_store(proc, d, dst_slice); + ssa_emit_store(proc, s, src_slice); - ssaValue *len_dst = ssa_slice_len(proc, dst_slice); - ssaValue *len_src = ssa_slice_len(proc, src_slice); + ssaValue *dst = ssa_emit_conv(proc, ssa_slice_elem(proc, d), t_rawptr); + ssaValue *src = ssa_emit_conv(proc, ssa_slice_elem(proc, s), t_rawptr); + + ssaValue *len_dst = ssa_slice_len(proc, d); + ssaValue *len_src = ssa_slice_len(proc, s); Token lt = {Token_Lt}; ssaValue *cond = ssa_emit_comp(proc, lt, len_dst, len_src); @@ -1795,6 +1800,51 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue return ssa_emit(proc, ssa_make_instr_shuffle_vector(proc, vector, indices, index_count)); } break; + + case BuiltinProc_ptr_offset: { + ssaValue *ptr = ssa_build_expr(proc, ce->arg_list); + ssaValue *offset = ssa_build_expr(proc, ce->arg_list->next); + return ssa_emit_ptr_offset(proc, ptr, offset); + } break; + + case BuiltinProc_ptr_sub: { + ssaValue *ptr_a = ssa_build_expr(proc, ce->arg_list); + ssaValue *ptr_b = ssa_build_expr(proc, ce->arg_list->next); + Type *ptr_type = get_base_type(ssa_type(ptr_a)); + GB_ASSERT(ptr_type->kind == Type_Pointer); + isize elem_size = type_size_of(proc->module->sizes, proc->module->allocator, ptr_type->Pointer.elem); + Token sub = {Token_Sub}; + ssaValue *v = ssa_emit_arith(proc, sub, ptr_a, ptr_b, t_int); + if (elem_size > 1) { + Token quo = {Token_Quo}; + ssaValue *ez = ssa_make_value_constant(proc->module->allocator, t_int, + make_exact_value_integer(elem_size)); + v = ssa_emit_arith(proc, quo, v, ez, t_int); + } + + return v; + } break; + + case BuiltinProc_slice_ptr: { + ssaValue *ptr = ssa_build_expr(proc, ce->arg_list); + ssaValue *len = ssa_build_expr(proc, ce->arg_list->next); + ssaValue *cap = len; + + len = ssa_emit_conv(proc, len, t_int); + + if (ce->arg_list->next->next != NULL) { + cap = ssa_build_expr(proc, ce->arg_list->next->next); + cap = ssa_emit_conv(proc, cap, t_int); + } + + + Type *slice_type = make_type_slice(proc->module->allocator, type_deref(ssa_type(ptr))); + ssaValue *slice = ssa_add_local_generated(proc, slice_type); + ssa_emit_store(proc, ssa_emit_struct_gep(proc, slice, v_zero32, ssa_type(ptr)), ptr); + ssa_emit_store(proc, ssa_emit_struct_gep(proc, slice, v_one32, t_int), len); + ssa_emit_store(proc, ssa_emit_struct_gep(proc, slice, v_two32, t_int), cap); + return ssa_emit_load(proc, slice); + } break; } } } @@ -2010,7 +2060,8 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { } } break; case Type_Pointer: { - elem = ssa_emit_load(proc, ssa_build_addr(proc, ie->expr).addr); + ssaValue *array = ssa_emit_load(proc, ssa_build_expr(proc, ie->expr)); + elem = ssa_array_elem(proc, array); } break; } @@ -2050,18 +2101,24 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { case_end; case_ast_node(de, DerefExpr, expr); - ssaValue *e = ssa_emit_load(proc, ssa_build_addr(proc, de->expr).addr); - ssaValue *gep = ssa_make_instr_get_element_ptr(proc, e, NULL, NULL, 0, false); + ssaValue *e = ssa_build_expr(proc, de->expr); + ssaValue *gep = ssa_emit_zero_gep(proc, e); + // HACK(bill): need to deref here as stack variables are of type pointer + // and addresses are already pointers + // TODO(bill): Completely redo the type system for SSA Type *t = type_deref(ssa_type(e)); gep->Instr.GetElementPtr.result_type = t; gep->Instr.GetElementPtr.elem_type = t; - ssaValue *v = ssa_emit(proc, gep); - return ssa_make_addr(v, expr); + return ssa_make_addr(gep, expr); case_end; } + TokenPos token_pos = ast_node_token(expr).pos; GB_PANIC("Unexpected address expression\n" - "\tAstNode: %.*s\n", LIT(ast_node_strings[expr->kind])); + "\tAstNode: %.*s @ " + "%.*s(%td:%td)\n", + LIT(ast_node_strings[expr->kind]), + LIT(token_pos.file), token_pos.line, token_pos.column); return ssa_make_addr(NULL, NULL); diff --git a/src/unicode.cpp b/src/unicode.cpp index 1495101fc..cf415d86b 100644 --- a/src/unicode.cpp +++ b/src/unicode.cpp @@ -2,6 +2,8 @@ #pragma warning(disable: 4245) #include "utf8proc/utf8proc.h" +// #define UTF8PROC_IMPLEMENTATION +// #include "utf8proc/utf8proc_new.h" #pragma warning(pop)