authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-02-04 15:26:27-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-02-04 15:26:27-07:00
logfcbeaddbb2321cd1006e0e007144b0f116de80be
tree155c3ea33cc38157b62b131833144b87aa08f1a7
parentb87d0abefeeeed4d9ce981971a5e33a6d0932529

codegen: fix switch expressions for enums with payloads


2 files changed, 59 insertions(+), 14 deletions(-)

src/codegen.cpp+47-10
......@@ -1256,8 +1256,12 @@ static LLVMValueRef gen_cmp_expr(CodeGen *g, AstNode *node) {
12561256 op1_type->data.integral.is_signed);
12571257 return LLVMBuildICmp(g->builder, pred, val1, val2, "");
12581258 } else if (op1_type->id == TypeTableEntryIdEnum) {
1259 LLVMIntPredicate pred = cmp_op_to_int_predicate(node->data.bin_op_expr.bin_op, false);
1260 return LLVMBuildICmp(g->builder, pred, val1, val2, "");
1259 if (op1_type->data.enumeration.gen_field_count == 0) {
1260 LLVMIntPredicate pred = cmp_op_to_int_predicate(node->data.bin_op_expr.bin_op, false);
1261 return LLVMBuildICmp(g->builder, pred, val1, val2, "");
1262 } else {
1263 zig_unreachable();
1264 }
12611265 } else {
12621266 zig_unreachable();
12631267 }
......@@ -2309,9 +2313,25 @@ static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) {
23092313static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {
23102314 assert(node->type == NodeTypeSwitchExpr);
23112315
2312 LLVMValueRef target_value = gen_expr(g, node->data.switch_expr.expr);
2316 TypeTableEntry *target_type = get_expr_type(node->data.switch_expr.expr);
2317 LLVMValueRef target_value_handle = gen_expr(g, node->data.switch_expr.expr);
2318 LLVMValueRef target_value;
2319 if (handle_is_ptr(target_type)) {
2320 if (target_type->id == TypeTableEntryIdEnum) {
2321 add_debug_source_node(g, node);
2322 LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, target_value_handle, 0, "");
2323 target_value = LLVMBuildLoad(g->builder, tag_field_ptr, "");
2324 } else {
2325 zig_unreachable();
2326 }
2327 } else {
2328 target_value = target_value_handle;
2329 }
2330
23132331
2314 bool end_unreachable = (get_expr_type(node)->id == TypeTableEntryIdUnreachable);
2332 TypeTableEntry *switch_type = get_expr_type(node);
2333 bool result_has_bits = type_has_bits(switch_type);
2334 bool end_unreachable = (switch_type->id == TypeTableEntryIdUnreachable);
23152335
23162336 LLVMBasicBlockRef end_block = end_unreachable ?
23172337 nullptr : LLVMAppendBasicBlock(g->cur_fn->fn_value, "SwitchEnd");
......@@ -2338,7 +2358,21 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {
23382358 AstNode *item_node = prong_node->data.switch_prong.items.at(item_i);
23392359 assert(item_node->type != NodeTypeSwitchRange);
23402360 assert(get_resolved_expr(item_node)->const_val.ok);
2341 LLVMValueRef val = gen_expr(g, item_node);
2361 LLVMValueRef val_handle = gen_expr(g, item_node);
2362 LLVMValueRef val;
2363 if (handle_is_ptr(target_type)) {
2364 if (target_type->id == TypeTableEntryIdEnum) {
2365 ConstExprValue *item_const_val = &get_resolved_expr(item_node)->const_val;
2366 assert(item_const_val->ok);
2367 assert(get_expr_type(item_node)->id == TypeTableEntryIdEnum);
2368 val = LLVMConstInt(target_type->data.enumeration.tag_type->type_ref,
2369 item_const_val->data.x_enum.tag, false);
2370 } else {
2371 zig_unreachable();
2372 }
2373 } else {
2374 val = val_handle;
2375 }
23422376 LLVMAddCase(switch_instr, val, prong_block);
23432377 }
23442378 }
......@@ -2367,11 +2401,14 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {
23672401
23682402 LLVMPositionBuilderAtEnd(g->builder, end_block);
23692403
2370 add_debug_source_node(g, node);
2371 LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(incoming_values.at(0)), "");
2372 LLVMAddIncoming(phi, incoming_values.items, incoming_blocks.items, incoming_values.length);
2373
2374 return phi;
2404 if (result_has_bits) {
2405 add_debug_source_node(g, node);
2406 LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(incoming_values.at(0)), "");
2407 LLVMAddIncoming(phi, incoming_values.items, incoming_blocks.items, incoming_values.length);
2408 return phi;
2409 } else {
2410 return nullptr;
2411 }
23752412}
23762413
23772414static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
test/self_hosted.zig+12-4
......@@ -51,16 +51,24 @@ error SecondError;
5151
5252#attribute("test")
5353fn constant_enum_with_payload() {
54 should_be_empty(AnEnumWithPayload.Empty);
55 should_be_not_empty(AnEnumWithPayload.Full(13));
54 var empty = AnEnumWithPayload.Empty;
55 var full = AnEnumWithPayload.Full(13);
56 should_be_empty(empty);
57 should_be_not_empty(full);
5658}
5759
5860fn should_be_empty(x: AnEnumWithPayload) {
59 if (x != AnEnumWithPayload.Empty) unreachable{}
61 switch (x) {
62 AnEnumWithPayload.Empty => {},
63 else => unreachable{},
64 }
6065}
6166
6267fn should_be_not_empty(x: AnEnumWithPayload) {
63 if (x == AnEnumWithPayload.Empty) unreachable{}
68 switch (x) {
69 AnEnumWithPayload.Empty => unreachable{},
70 else => {},
71 }
6472}
6573
6674enum AnEnumWithPayload {