authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-26 05:46:18+00:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-07-26 05:46:18+00:00
loga36772ee642607326c48a4ddb3acfa600cb502b6
tree32765a05208c92f985f82beec6fb45d4f19e86e8
parentf050150ffaef7bc5e72e23c48d46617f640117e2
parentdcc406deff0fb4ee3c2cd1f4ff8614e972a8ea7a
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #5693 from antlilja/switch-unreachable-else

Add error message for unreachable else prong in switch

7 files changed, 122 insertions(+), 15 deletions(-)

lib/std/zig/string_literal.zig-1
......@@ -104,7 +104,6 @@ pub fn parse(
104104 return error.InvalidCharacter;
105105 },
106106 },
107 else => unreachable,
108107 }
109108 }
110109 unreachable;
src-self-hosted/translate_c.zig-1
......@@ -2864,7 +2864,6 @@ fn transCharLiteral(
28642864 "TODO: support character literal kind {}",
28652865 .{kind},
28662866 ),
2867 else => unreachable,
28682867 };
28692868 if (suppress_as == .no_as) {
28702869 return maybeSuppressResult(rp, scope, result_used, int_lit_node);
src/all_types.hpp+1-1
......@@ -4110,7 +4110,7 @@ struct IrInstSrcCheckSwitchProngs {
41104110 IrInstSrc *target_value;
41114111 IrInstSrcCheckSwitchProngsRange *ranges;
41124112 size_t range_count;
4113 bool have_else_prong;
4113 AstNode* else_prong;
41144114 bool have_underscore_prong;
41154115};
41164116
src/ir.cpp+24-10
......@@ -4299,14 +4299,14 @@ static IrInstGen *ir_build_err_to_int_gen(IrAnalyze *ira, Scope *scope, AstNode
42994299
43004300static IrInstSrc *ir_build_check_switch_prongs(IrBuilderSrc *irb, Scope *scope, AstNode *source_node,
43014301 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)
43034303{
43044304 IrInstSrcCheckSwitchProngs *instruction = ir_build_instruction<IrInstSrcCheckSwitchProngs>(
43054305 irb, scope, source_node);
43064306 instruction->target_value = target_value;
43074307 instruction->ranges = ranges;
43084308 instruction->range_count = range_count;
4309 instruction->have_else_prong = have_else_prong;
4309 instruction->else_prong = else_prong;
43104310 instruction->have_underscore_prong = have_underscore_prong;
43114311
43124312 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
93469346 }
93479347
93489348 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);
93509350
93519351 IrInstSrc *br_instruction;
93529352 if (cases.length == 0) {
......@@ -28827,7 +28827,7 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
2882728827 buf_ptr(enum_field->name)));
2882828828 }
2882928829 }
28830 } else if (!instruction->have_else_prong) {
28830 } else if (instruction->else_prong == nullptr) {
2883128831 if (switch_type->data.enumeration.non_exhaustive) {
2883228832 ir_add_error(ira, &instruction->base.base,
2883328833 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,
2884228842 buf_ptr(enum_field->name)));
2884328843 }
2884428844 }
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;
2884528849 }
2884628850 } else if (switch_type->id == ZigTypeIdErrorSet) {
2884728851 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,
2888828892 }
2888928893 field_prev_uses[start_index] = start_value->base.source_node;
2889028894 }
28891 if (!instruction->have_else_prong) {
28895 if (instruction->else_prong == nullptr) {
2889228896 if (type_is_global_error_set(switch_type)) {
2889328897 ir_add_error(ira, &instruction->base.base,
2889428898 buf_sprintf("else prong required when switching on type 'anyerror'"));
......@@ -28950,16 +28954,20 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
2895028954 return ira->codegen->invalid_inst_gen;
2895128955 }
2895228956 }
28953 if (!instruction->have_else_prong) {
28957
2895428958 BigInt min_val;
2895528959 eval_min_max_value_int(ira->codegen, switch_type, &min_val, false);
2895628960 BigInt max_val;
2895728961 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) {
2895928964 ir_add_error(ira, &instruction->base.base, buf_sprintf("switch must handle all possibilities"));
2896028965 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;
2896128970 }
28962 }
2896328971 } else if (switch_type->id == ZigTypeIdBool) {
2896428972 int seenTrue = 0;
2896528973 int seenFalse = 0;
......@@ -28989,11 +28997,17 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
2898928997 return ira->codegen->invalid_inst_gen;
2899028998 }
2899128999 }
28992 if (((seenTrue < 1) || (seenFalse < 1)) && !instruction->have_else_prong) {
29000 if (((seenTrue < 1) || (seenFalse < 1)) && instruction->else_prong == nullptr) {
2899329001 ir_add_error(ira, &instruction->base.base, buf_sprintf("switch must handle all possibilities"));
2899429002 return ira->codegen->invalid_inst_gen;
2899529003 }
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) {
2899729011 ir_add_error(ira, &instruction->base.base,
2899829012 buf_sprintf("else prong required when switching on type '%s'", buf_ptr(&switch_type->name)));
2899929013 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
21752175 fprintf(irp->f, "...");
21762176 ir_print_other_inst_src(irp, instruction->ranges[i].end);
21772177 }
2178 const char *have_else_str = instruction->have_else_prong ? "yes" : "no";
2178 const char *have_else_str = instruction->else_prong != nullptr ? "yes" : "no";
21792179 fprintf(irp->f, ")else:%s", have_else_str);
21802180}
21812181
test/compile_errors.zig+96
......@@ -509,6 +509,102 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
509509 "tmp.zig:12:5: error: switch on non-exhaustive enum must include `else` or `_` prong",
510510 });
511511
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
512608 cases.addTest("@export with empty name string",
513609 \\pub export fn entry() void { }
514610 \\comptime {
test/stage1/behavior/bugs/1111.zig-1
......@@ -7,6 +7,5 @@ test "issue 1111 fixed" {
77
88 switch (v) {
99 Foo.Bar => return,
10 else => return,
1110 }
1211}