aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGinger Bill <bill@gingerbill.org>2017-04-13 22:42:36 +0100
committerGinger Bill <bill@gingerbill.org>2017-04-13 22:42:36 +0100
commit0d2dbee84e937ccf411787f9dda72e541db3fd20 (patch)
treea0f8853f682e46161c38273c727896b1f998ade6 /src
parentd8d22e34dd63547cb6492e8e15b55fcaec4cb3e5 (diff)
Fix addressing mode rules for `match in` statements
Diffstat (limited to 'src')
-rw-r--r--src/check_expr.c3
-rw-r--r--src/check_stmt.c12
-rw-r--r--src/entity.c1
-rw-r--r--src/ir.c13
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);