From 0d2dbee84e937ccf411787f9dda72e541db3fd20 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Thu, 13 Apr 2017 22:42:36 +0100 Subject: [PATCH] Fix addressing mode rules for `match in` statements --- src/check_expr.c | 3 +++ src/check_stmt.c | 12 +++++++++++- src/entity.c | 1 + src/ir.c | 13 +++++++++++-- 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/check_expr.c b/src/check_expr.c index e1423073b..24ac6dfc1 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -1142,6 +1142,9 @@ Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type * return e; } o->mode = Addressing_Variable; + if (e->flags & EntityFlag_Value) { + o->mode = Addressing_Value; + } if (e->Variable.is_immutable) { o->mode = Addressing_Immutable; } diff --git a/src/check_stmt.c b/src/check_stmt.c index 0ad48864a..c66729005 100644 --- a/src/check_stmt.c +++ b/src/check_stmt.c @@ -1058,6 +1058,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { break; } + bool is_ptr = is_type_pointer(x.type); + // NOTE(bill): Check for multiple defaults AstNode *first_default = NULL; ast_node(bs, BlockStmt, ms->body); @@ -1153,6 +1155,13 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { } } + if (is_ptr && + !is_type_any(type_deref(x.type)) && + cc->list.count == 1 && + case_type != NULL) { + case_type = make_type_pointer(c->allocator, case_type); + } + if (cc->list.count > 1) { case_type = NULL; } @@ -1163,8 +1172,9 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { check_open_scope(c, stmt); { - Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, lhs->Ident, case_type, true); + Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, lhs->Ident, case_type, false); tag_var->flags |= EntityFlag_Used; + tag_var->flags |= EntityFlag_Value; add_entity(c, c->context.scope, lhs, tag_var); add_entity_use(c, lhs, tag_var); add_implicit_entity(c, stmt, tag_var); diff --git a/src/entity.c b/src/entity.c index aa1b8f52a..d721df221 100644 --- a/src/entity.c +++ b/src/entity.c @@ -40,6 +40,7 @@ typedef enum EntityFlag { EntityFlag_Ellipsis = 1<<6, EntityFlag_NoAlias = 1<<7, EntityFlag_TypeField = 1<<8, + EntityFlag_Value = 1<<9, } EntityFlag; // Zero value means the overloading process is not yet done diff --git a/src/ir.c b/src/ir.c index e09426229..c0f36b92c 100644 --- a/src/ir.c +++ b/src/ir.c @@ -6239,7 +6239,13 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { ir_start_block(proc, body); if (cc->list.count == 1) { - Type *ct = make_type_pointer(proc->module->allocator, case_entity->type); + bool any_or_not_ptr = is_type_any(type_deref(parent_type)) || !is_parent_ptr; + + Type *ct = case_entity->type; + if (any_or_not_ptr) { + ct = make_type_pointer(proc->module->allocator, ct); + } + GB_ASSERT_MSG(is_type_pointer(ct), "%s", type_to_string(ct)); irValue *data = NULL; if (match_type_kind == MatchType_Union) { data = union_data; @@ -6247,7 +6253,10 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { irValue *any_data = ir_emit_load(proc, ir_emit_struct_ep(proc, parent_ptr, 1)); data = any_data; } - value = ir_emit_load(proc, ir_emit_conv(proc, data, ct)); + value = ir_emit_conv(proc, data, ct); + if (any_or_not_ptr) { + value = ir_emit_load(proc, value); + } } ir_store_type_case_implicit(proc, clause, value);