| author | |
| committer | |
| log | d3e67d99216d3dd6c18259c17652fcad54aebc21 |
| tree | c61934554aeab9798a0bc8ae29ab95c80b54eefe |
| parent | b9f37ffe19e30da1fd79cd01dbb6191ec2733b5c |
| parent | cae93c860bc2c599618482a4190daf619a0c69e2 |
| signature | Signed by PGP key 4AEE18F83AFDEB23 |
Two switch-related patches4 files changed, 72 insertions(+), 3 deletions(-)
src/codegen.cpp+19-3| ... | ... | @@ -4876,14 +4876,30 @@ static LLVMValueRef ir_render_pop_count(CodeGen *g, IrExecutable *executable, Ir |
| 4876 | 4876 | } |
| 4877 | 4877 | |
| 4878 | 4878 | static LLVMValueRef ir_render_switch_br(CodeGen *g, IrExecutable *executable, IrInstructionSwitchBr *instruction) { |
| 4879 | LLVMValueRef target_value = ir_llvm_value(g, instruction->target_value); | |
| 4879 | ZigType *target_type = instruction->target_value->value->type; | |
| 4880 | 4880 | LLVMBasicBlockRef else_block = instruction->else_block->llvm_block; |
| 4881 | ||
| 4882 | LLVMValueRef target_value = ir_llvm_value(g, instruction->target_value); | |
| 4883 | if (target_type->id == ZigTypeIdPointer) { | |
| 4884 | const ZigType *usize = g->builtin_types.entry_usize; | |
| 4885 | target_value = LLVMBuildPtrToInt(g->builder, target_value, usize->llvm_type, ""); | |
| 4886 | } | |
| 4887 | ||
| 4881 | 4888 | LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, target_value, else_block, |
| 4882 | (unsigned)instruction->case_count); | |
| 4889 | (unsigned)instruction->case_count); | |
| 4890 | ||
| 4883 | 4891 | for (size_t i = 0; i < instruction->case_count; i += 1) { |
| 4884 | 4892 | IrInstructionSwitchBrCase *this_case = &instruction->cases[i]; |
| 4885 | LLVMAddCase(switch_instr, ir_llvm_value(g, this_case->value), this_case->block->llvm_block); | |
| 4893 | ||
| 4894 | LLVMValueRef case_value = ir_llvm_value(g, this_case->value); | |
| 4895 | if (target_type->id == ZigTypeIdPointer) { | |
| 4896 | const ZigType *usize = g->builtin_types.entry_usize; | |
| 4897 | case_value = LLVMBuildPtrToInt(g->builder, case_value, usize->llvm_type, ""); | |
| 4898 | } | |
| 4899 | ||
| 4900 | LLVMAddCase(switch_instr, case_value, this_case->block->llvm_block); | |
| 4886 | 4901 | } |
| 4902 | ||
| 4887 | 4903 | return nullptr; |
| 4888 | 4904 | } |
| 4889 | 4905 |
src/ir.cpp+12| ... | ... | @@ -26394,6 +26394,7 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, |
| 26394 | 26394 | if (type_is_invalid(end_value->value->type)) |
| 26395 | 26395 | return ira->codegen->invalid_instruction; |
| 26396 | 26396 | |
| 26397 | assert(start_value->value->type->id == ZigTypeIdEnum); | |
| 26397 | 26398 | BigInt start_index; |
| 26398 | 26399 | bigint_init_bigint(&start_index, &start_value->value->data.x_enum_tag); |
| 26399 | 26400 | |
| ... | ... | @@ -26401,6 +26402,11 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, |
| 26401 | 26402 | BigInt end_index; |
| 26402 | 26403 | bigint_init_bigint(&end_index, &end_value->value->data.x_enum_tag); |
| 26403 | 26404 | |
| 26405 | if (bigint_cmp(&start_index, &end_index) == CmpGT) { | |
| 26406 | ir_add_error(ira, start_value, | |
| 26407 | buf_sprintf("range start value is greater than the end value")); | |
| 26408 | } | |
| 26409 | ||
| 26404 | 26410 | BigInt field_index; |
| 26405 | 26411 | bigint_init_bigint(&field_index, &start_index); |
| 26406 | 26412 | for (;;) { |
| ... | ... | @@ -26530,6 +26536,12 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, |
| 26530 | 26536 | |
| 26531 | 26537 | assert(start_val->type->id == ZigTypeIdInt || start_val->type->id == ZigTypeIdComptimeInt); |
| 26532 | 26538 | assert(end_val->type->id == ZigTypeIdInt || end_val->type->id == ZigTypeIdComptimeInt); |
| 26539 | ||
| 26540 | if (bigint_cmp(&start_val->data.x_bigint, &end_val->data.x_bigint) == CmpGT) { | |
| 26541 | ir_add_error(ira, start_value, | |
| 26542 | buf_sprintf("range start value is greater than the end value")); | |
| 26543 | } | |
| 26544 | ||
| 26533 | 26545 | AstNode *prev_node = rangeset_add_range(&rs, &start_val->data.x_bigint, &end_val->data.x_bigint, |
| 26534 | 26546 | start_value->source_node); |
| 26535 | 26547 | if (prev_node != nullptr) { |
test/compile_errors.zig+14| ... | ... | @@ -2,6 +2,20 @@ const tests = @import("tests.zig"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | 3 | |
| 4 | 4 | pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5 | cases.addTest("switch ranges endpoints are validated", | |
| 6 | \\pub export fn entry() void { | |
| 7 | \\ var x: i32 = 0; | |
| 8 | \\ switch (x) { | |
| 9 | \\ 6...1 => {}, | |
| 10 | \\ -1...-5 => {}, | |
| 11 | \\ else => unreachable, | |
| 12 | \\ } | |
| 13 | \\} | |
| 14 | , &[_][]const u8{ | |
| 15 | "tmp.zig:4:9: error: range start value is greater than the end value", | |
| 16 | "tmp.zig:5:9: error: range start value is greater than the end value", | |
| 17 | }); | |
| 18 | ||
| 5 | 19 | cases.addTest("errors in for loop bodies are propagated", |
| 6 | 20 | \\pub export fn entry() void { |
| 7 | 21 | \\ var arr: [100]u8 = undefined; |
test/stage1/behavior/switch.zig+27| ... | ... | @@ -452,3 +452,30 @@ test "switch on global mutable var isn't constant-folded" { |
| 452 | 452 | poll(); |
| 453 | 453 | } |
| 454 | 454 | } |
| 455 | ||
| 456 | test "switch on pointer type" { | |
| 457 | const S = struct { | |
| 458 | const X = struct { | |
| 459 | field: u32, | |
| 460 | }; | |
| 461 | ||
| 462 | const P1 = @intToPtr(*X, 0x400); | |
| 463 | const P2 = @intToPtr(*X, 0x800); | |
| 464 | const P3 = @intToPtr(*X, 0xC00); | |
| 465 | ||
| 466 | fn doTheTest(arg: *X) i32 { | |
| 467 | switch (arg) { | |
| 468 | P1 => return 1, | |
| 469 | P2 => return 2, | |
| 470 | else => return 3, | |
| 471 | } | |
| 472 | } | |
| 473 | }; | |
| 474 | ||
| 475 | expect(1 == S.doTheTest(S.P1)); | |
| 476 | expect(2 == S.doTheTest(S.P2)); | |
| 477 | expect(3 == S.doTheTest(S.P3)); | |
| 478 | comptime expect(1 == S.doTheTest(S.P1)); | |
| 479 | comptime expect(2 == S.doTheTest(S.P2)); | |
| 480 | comptime expect(3 == S.doTheTest(S.P3)); | |
| 481 | } |