| author | |
| committer | |
| log | a36772ee642607326c48a4ddb3acfa600cb502b6 |
| tree | 32765a05208c92f985f82beec6fb45d4f19e86e8 |
| parent | f050150ffaef7bc5e72e23c48d46617f640117e2 |
| parent | dcc406deff0fb4ee3c2cd1f4ff8614e972a8ea7a |
| signature |
Add error message for unreachable else prong in switch7 files changed, 122 insertions(+), 15 deletions(-)
lib/std/zig/string_literal.zig-1| ... | ... | @@ -104,7 +104,6 @@ pub fn parse( |
| 104 | 104 | return error.InvalidCharacter; |
| 105 | 105 | }, |
| 106 | 106 | }, |
| 107 | else => unreachable, | |
| 108 | 107 | } |
| 109 | 108 | } |
| 110 | 109 | unreachable; |
src-self-hosted/translate_c.zig-1| ... | ... | @@ -2864,7 +2864,6 @@ fn transCharLiteral( |
| 2864 | 2864 | "TODO: support character literal kind {}", |
| 2865 | 2865 | .{kind}, |
| 2866 | 2866 | ), |
| 2867 | else => unreachable, | |
| 2868 | 2867 | }; |
| 2869 | 2868 | if (suppress_as == .no_as) { |
| 2870 | 2869 | return maybeSuppressResult(rp, scope, result_used, int_lit_node); |
src/all_types.hpp+1-1| ... | ... | @@ -4110,7 +4110,7 @@ struct IrInstSrcCheckSwitchProngs { |
| 4110 | 4110 | IrInstSrc *target_value; |
| 4111 | 4111 | IrInstSrcCheckSwitchProngsRange *ranges; |
| 4112 | 4112 | size_t range_count; |
| 4113 | bool have_else_prong; | |
| 4113 | AstNode* else_prong; | |
| 4114 | 4114 | bool have_underscore_prong; |
| 4115 | 4115 | }; |
| 4116 | 4116 |
src/ir.cpp+24-10| ... | ... | @@ -4299,14 +4299,14 @@ static IrInstGen *ir_build_err_to_int_gen(IrAnalyze *ira, Scope *scope, AstNode |
| 4299 | 4299 | |
| 4300 | 4300 | static IrInstSrc *ir_build_check_switch_prongs(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, |
| 4301 | 4301 | IrInstSrc *target_value, IrInstSrcCheckSwitchProngsRange *ranges, size_t range_count, |
| 4302 | bool have_else_prong, bool have_underscore_prong) | |
| 4302 | AstNode* else_prong, bool have_underscore_prong) | |
| 4303 | 4303 | { |
| 4304 | 4304 | IrInstSrcCheckSwitchProngs *instruction = ir_build_instruction<IrInstSrcCheckSwitchProngs>( |
| 4305 | 4305 | irb, scope, source_node); |
| 4306 | 4306 | instruction->target_value = target_value; |
| 4307 | 4307 | instruction->ranges = ranges; |
| 4308 | 4308 | instruction->range_count = range_count; |
| 4309 | instruction->have_else_prong = have_else_prong; | |
| 4309 | instruction->else_prong = else_prong; | |
| 4310 | 4310 | instruction->have_underscore_prong = have_underscore_prong; |
| 4311 | 4311 | |
| 4312 | 4312 | ir_ref_instruction(target_value, irb->current_basic_block); |
| ... | ... | @@ -9346,7 +9346,7 @@ static IrInstSrc *ir_gen_switch_expr(IrBuilderSrc *irb, Scope *scope, AstNode *n |
| 9346 | 9346 | } |
| 9347 | 9347 | |
| 9348 | 9348 | IrInstSrc *switch_prongs_void = ir_build_check_switch_prongs(irb, scope, node, target_value, |
| 9349 | check_ranges.items, check_ranges.length, else_prong != nullptr, underscore_prong != nullptr); | |
| 9349 | check_ranges.items, check_ranges.length, else_prong, underscore_prong != nullptr); | |
| 9350 | 9350 | |
| 9351 | 9351 | IrInstSrc *br_instruction; |
| 9352 | 9352 | if (cases.length == 0) { |
| ... | ... | @@ -28827,7 +28827,7 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, |
| 28827 | 28827 | buf_ptr(enum_field->name))); |
| 28828 | 28828 | } |
| 28829 | 28829 | } |
| 28830 | } else if (!instruction->have_else_prong) { | |
| 28830 | } else if (instruction->else_prong == nullptr) { | |
| 28831 | 28831 | if (switch_type->data.enumeration.non_exhaustive) { |
| 28832 | 28832 | ir_add_error(ira, &instruction->base.base, |
| 28833 | 28833 | buf_sprintf("switch on non-exhaustive enum must include `else` or `_` prong")); |
| ... | ... | @@ -28842,6 +28842,10 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, |
| 28842 | 28842 | buf_ptr(enum_field->name))); |
| 28843 | 28843 | } |
| 28844 | 28844 | } |
| 28845 | } else if(!switch_type->data.enumeration.non_exhaustive && switch_type->data.enumeration.src_field_count == instruction->range_count) { | |
| 28846 | ir_add_error_node(ira, instruction->else_prong, | |
| 28847 | buf_sprintf("unreachable else prong, all cases already handled")); | |
| 28848 | return ira->codegen->invalid_inst_gen; | |
| 28845 | 28849 | } |
| 28846 | 28850 | } else if (switch_type->id == ZigTypeIdErrorSet) { |
| 28847 | 28851 | if (!resolve_inferred_error_set(ira->codegen, switch_type, target_value->base.source_node)) { |
| ... | ... | @@ -28888,7 +28892,7 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, |
| 28888 | 28892 | } |
| 28889 | 28893 | field_prev_uses[start_index] = start_value->base.source_node; |
| 28890 | 28894 | } |
| 28891 | if (!instruction->have_else_prong) { | |
| 28895 | if (instruction->else_prong == nullptr) { | |
| 28892 | 28896 | if (type_is_global_error_set(switch_type)) { |
| 28893 | 28897 | ir_add_error(ira, &instruction->base.base, |
| 28894 | 28898 | buf_sprintf("else prong required when switching on type 'anyerror'")); |
| ... | ... | @@ -28950,16 +28954,20 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, |
| 28950 | 28954 | return ira->codegen->invalid_inst_gen; |
| 28951 | 28955 | } |
| 28952 | 28956 | } |
| 28953 | if (!instruction->have_else_prong) { | |
| 28957 | ||
| 28954 | 28958 | BigInt min_val; |
| 28955 | 28959 | eval_min_max_value_int(ira->codegen, switch_type, &min_val, false); |
| 28956 | 28960 | BigInt max_val; |
| 28957 | 28961 | eval_min_max_value_int(ira->codegen, switch_type, &max_val, true); |
| 28958 | if (!rangeset_spans(&rs, &min_val, &max_val)) { | |
| 28962 | bool handles_all_cases = rangeset_spans(&rs, &min_val, &max_val); | |
| 28963 | if (!handles_all_cases && instruction->else_prong == nullptr) { | |
| 28959 | 28964 | ir_add_error(ira, &instruction->base.base, buf_sprintf("switch must handle all possibilities")); |
| 28960 | 28965 | return ira->codegen->invalid_inst_gen; |
| 28966 | } else if(handles_all_cases && instruction->else_prong != nullptr) { | |
| 28967 | ir_add_error_node(ira, instruction->else_prong, | |
| 28968 | buf_sprintf("unreachable else prong, all cases already handled")); | |
| 28969 | return ira->codegen->invalid_inst_gen; | |
| 28961 | 28970 | } |
| 28962 | } | |
| 28963 | 28971 | } else if (switch_type->id == ZigTypeIdBool) { |
| 28964 | 28972 | int seenTrue = 0; |
| 28965 | 28973 | int seenFalse = 0; |
| ... | ... | @@ -28989,11 +28997,17 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, |
| 28989 | 28997 | return ira->codegen->invalid_inst_gen; |
| 28990 | 28998 | } |
| 28991 | 28999 | } |
| 28992 | if (((seenTrue < 1) || (seenFalse < 1)) && !instruction->have_else_prong) { | |
| 29000 | if (((seenTrue < 1) || (seenFalse < 1)) && instruction->else_prong == nullptr) { | |
| 28993 | 29001 | ir_add_error(ira, &instruction->base.base, buf_sprintf("switch must handle all possibilities")); |
| 28994 | 29002 | return ira->codegen->invalid_inst_gen; |
| 28995 | 29003 | } |
| 28996 | } else if (!instruction->have_else_prong) { | |
| 29004 | ||
| 29005 | if(seenTrue == 1 && seenFalse == 1 && instruction->else_prong != nullptr) { | |
| 29006 | ir_add_error_node(ira, instruction->else_prong, | |
| 29007 | buf_sprintf("unreachable else prong, all cases already handled")); | |
| 29008 | return ira->codegen->invalid_inst_gen; | |
| 29009 | } | |
| 29010 | } else if (instruction->else_prong == nullptr) { | |
| 28997 | 29011 | ir_add_error(ira, &instruction->base.base, |
| 28998 | 29012 | buf_sprintf("else prong required when switching on type '%s'", buf_ptr(&switch_type->name))); |
| 28999 | 29013 | return ira->codegen->invalid_inst_gen; |
src/ir_print.cpp+1-1| ... | ... | @@ -2175,7 +2175,7 @@ static void ir_print_check_switch_prongs(IrPrintSrc *irp, IrInstSrcCheckSwitchPr |
| 2175 | 2175 | fprintf(irp->f, "..."); |
| 2176 | 2176 | ir_print_other_inst_src(irp, instruction->ranges[i].end); |
| 2177 | 2177 | } |
| 2178 | const char *have_else_str = instruction->have_else_prong ? "yes" : "no"; | |
| 2178 | const char *have_else_str = instruction->else_prong != nullptr ? "yes" : "no"; | |
| 2179 | 2179 | fprintf(irp->f, ")else:%s", have_else_str); |
| 2180 | 2180 | } |
| 2181 | 2181 |
test/compile_errors.zig+96| ... | ... | @@ -509,6 +509,102 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 509 | 509 | "tmp.zig:12:5: error: switch on non-exhaustive enum must include `else` or `_` prong", |
| 510 | 510 | }); |
| 511 | 511 | |
| 512 | cases.add("switch expression - unreachable else prong (bool)", | |
| 513 | \\fn foo(x: bool) void { | |
| 514 | \\ switch (x) { | |
| 515 | \\ true => {}, | |
| 516 | \\ false => {}, | |
| 517 | \\ else => {}, | |
| 518 | \\ } | |
| 519 | \\} | |
| 520 | \\export fn entry() usize { return @sizeOf(@TypeOf(foo)); } | |
| 521 | , &[_][]const u8{ | |
| 522 | "tmp.zig:5:9: error: unreachable else prong, all cases already handled", | |
| 523 | }); | |
| 524 | ||
| 525 | cases.add("switch expression - unreachable else prong (u1)", | |
| 526 | \\fn foo(x: u1) void { | |
| 527 | \\ switch (x) { | |
| 528 | \\ 0 => {}, | |
| 529 | \\ 1 => {}, | |
| 530 | \\ else => {}, | |
| 531 | \\ } | |
| 532 | \\} | |
| 533 | \\export fn entry() usize { return @sizeOf(@TypeOf(foo)); } | |
| 534 | , &[_][]const u8{ | |
| 535 | "tmp.zig:5:9: error: unreachable else prong, all cases already handled", | |
| 536 | }); | |
| 537 | ||
| 538 | cases.add("switch expression - unreachable else prong (u2)", | |
| 539 | \\fn foo(x: u2) void { | |
| 540 | \\ switch (x) { | |
| 541 | \\ 0 => {}, | |
| 542 | \\ 1 => {}, | |
| 543 | \\ 2 => {}, | |
| 544 | \\ 3 => {}, | |
| 545 | \\ else => {}, | |
| 546 | \\ } | |
| 547 | \\} | |
| 548 | \\export fn entry() usize { return @sizeOf(@TypeOf(foo)); } | |
| 549 | , &[_][]const u8{ | |
| 550 | "tmp.zig:7:9: error: unreachable else prong, all cases already handled", | |
| 551 | }); | |
| 552 | ||
| 553 | cases.add("switch expression - unreachable else prong (range u8)", | |
| 554 | \\fn foo(x: u8) void { | |
| 555 | \\ switch (x) { | |
| 556 | \\ 0 => {}, | |
| 557 | \\ 1 => {}, | |
| 558 | \\ 2 => {}, | |
| 559 | \\ 3 => {}, | |
| 560 | \\ 4...255 => {}, | |
| 561 | \\ else => {}, | |
| 562 | \\ } | |
| 563 | \\} | |
| 564 | \\export fn entry() usize { return @sizeOf(@TypeOf(foo)); } | |
| 565 | , &[_][]const u8{ | |
| 566 | "tmp.zig:8:9: error: unreachable else prong, all cases already handled", | |
| 567 | }); | |
| 568 | ||
| 569 | cases.add("switch expression - unreachable else prong (range i8)", | |
| 570 | \\fn foo(x: i8) void { | |
| 571 | \\ switch (x) { | |
| 572 | \\ -128...0 => {}, | |
| 573 | \\ 1 => {}, | |
| 574 | \\ 2 => {}, | |
| 575 | \\ 3 => {}, | |
| 576 | \\ 4...127 => {}, | |
| 577 | \\ else => {}, | |
| 578 | \\ } | |
| 579 | \\} | |
| 580 | \\export fn entry() usize { return @sizeOf(@TypeOf(foo)); } | |
| 581 | , &[_][]const u8{ | |
| 582 | "tmp.zig:8:9: error: unreachable else prong, all cases already handled", | |
| 583 | }); | |
| 584 | ||
| 585 | cases.add("switch expression - unreachable else prong (enum)", | |
| 586 | \\const TestEnum = enum{ T1, T2 }; | |
| 587 | \\ | |
| 588 | \\fn err(x: u8) TestEnum { | |
| 589 | \\ switch (x) { | |
| 590 | \\ 0 => return TestEnum.T1, | |
| 591 | \\ else => return TestEnum.T2, | |
| 592 | \\ } | |
| 593 | \\} | |
| 594 | \\ | |
| 595 | \\fn foo(x: u8) void { | |
| 596 | \\ switch (err(x)) { | |
| 597 | \\ TestEnum.T1 => {}, | |
| 598 | \\ TestEnum.T2 => {}, | |
| 599 | \\ else => {}, | |
| 600 | \\ } | |
| 601 | \\} | |
| 602 | \\ | |
| 603 | \\export fn entry() usize { return @sizeOf(@TypeOf(foo)); } | |
| 604 | , &[_][]const u8{ | |
| 605 | "tmp.zig:14:9: error: unreachable else prong, all cases already handled", | |
| 606 | }); | |
| 607 | ||
| 512 | 608 | cases.addTest("@export with empty name string", |
| 513 | 609 | \\pub export fn entry() void { } |
| 514 | 610 | \\comptime { |
test/stage1/behavior/bugs/1111.zig-1| ... | ... | @@ -7,6 +7,5 @@ test "issue 1111 fixed" { |
| 7 | 7 | |
| 8 | 8 | switch (v) { |
| 9 | 9 | Foo.Bar => return, |
| 10 | else => return, | |
| 11 | 10 | } |
| 12 | 11 | } |