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(...@@ -104,7 +104,6 @@ pub fn parse(
104 return error.InvalidCharacter;104 return error.InvalidCharacter;
105 },105 },
106 },106 },
107 else => unreachable,
108 }107 }
109 }108 }
110 unreachable;109 unreachable;
src-self-hosted/translate_c.zig-1
...@@ -2864,7 +2864,6 @@ fn transCharLiteral(...@@ -2864,7 +2864,6 @@ fn transCharLiteral(
2864 "TODO: support character literal kind {}",2864 "TODO: support character literal kind {}",
2865 .{kind},2865 .{kind},
2866 ),2866 ),
2867 else => unreachable,
2868 };2867 };
2869 if (suppress_as == .no_as) {2868 if (suppress_as == .no_as) {
2870 return maybeSuppressResult(rp, scope, result_used, int_lit_node);2869 return maybeSuppressResult(rp, scope, result_used, int_lit_node);
src/all_types.hpp+1-1
...@@ -4110,7 +4110,7 @@ struct IrInstSrcCheckSwitchProngs {...@@ -4110,7 +4110,7 @@ struct IrInstSrcCheckSwitchProngs {
4110 IrInstSrc *target_value;4110 IrInstSrc *target_value;
4111 IrInstSrcCheckSwitchProngsRange *ranges;4111 IrInstSrcCheckSwitchProngsRange *ranges;
4112 size_t range_count;4112 size_t range_count;
4113 bool have_else_prong;4113 AstNode* else_prong;
4114 bool have_underscore_prong;4114 bool have_underscore_prong;
4115};4115};
41164116
src/ir.cpp+24-10
...@@ -4299,14 +4299,14 @@ static IrInstGen *ir_build_err_to_int_gen(IrAnalyze *ira, Scope *scope, AstNode...@@ -4299,14 +4299,14 @@ static IrInstGen *ir_build_err_to_int_gen(IrAnalyze *ira, Scope *scope, AstNode
42994299
4300static IrInstSrc *ir_build_check_switch_prongs(IrBuilderSrc *irb, Scope *scope, AstNode *source_node,4300static IrInstSrc *ir_build_check_switch_prongs(IrBuilderSrc *irb, Scope *scope, AstNode *source_node,
4301 IrInstSrc *target_value, IrInstSrcCheckSwitchProngsRange *ranges, size_t range_count,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 IrInstSrcCheckSwitchProngs *instruction = ir_build_instruction<IrInstSrcCheckSwitchProngs>(4304 IrInstSrcCheckSwitchProngs *instruction = ir_build_instruction<IrInstSrcCheckSwitchProngs>(
4305 irb, scope, source_node);4305 irb, scope, source_node);
4306 instruction->target_value = target_value;4306 instruction->target_value = target_value;
4307 instruction->ranges = ranges;4307 instruction->ranges = ranges;
4308 instruction->range_count = range_count;4308 instruction->range_count = range_count;
4309 instruction->have_else_prong = have_else_prong;4309 instruction->else_prong = else_prong;
4310 instruction->have_underscore_prong = have_underscore_prong;4310 instruction->have_underscore_prong = have_underscore_prong;
43114311
4312 ir_ref_instruction(target_value, irb->current_basic_block);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,7 +9346,7 @@ static IrInstSrc *ir_gen_switch_expr(IrBuilderSrc *irb, Scope *scope, AstNode *n
9346 }9346 }
93479347
9348 IrInstSrc *switch_prongs_void = ir_build_check_switch_prongs(irb, scope, node, target_value,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);
93509350
9351 IrInstSrc *br_instruction;9351 IrInstSrc *br_instruction;
9352 if (cases.length == 0) {9352 if (cases.length == 0) {
...@@ -28827,7 +28827,7 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,...@@ -28827,7 +28827,7 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
28827 buf_ptr(enum_field->name)));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 if (switch_type->data.enumeration.non_exhaustive) {28831 if (switch_type->data.enumeration.non_exhaustive) {
28832 ir_add_error(ira, &instruction->base.base,28832 ir_add_error(ira, &instruction->base.base,
28833 buf_sprintf("switch on non-exhaustive enum must include `else` or `_` prong"));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,6 +28842,10 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
28842 buf_ptr(enum_field->name)));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 } else if (switch_type->id == ZigTypeIdErrorSet) {28850 } else if (switch_type->id == ZigTypeIdErrorSet) {
28847 if (!resolve_inferred_error_set(ira->codegen, switch_type, target_value->base.source_node)) {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,7 +28892,7 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
28888 }28892 }
28889 field_prev_uses[start_index] = start_value->base.source_node;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 if (type_is_global_error_set(switch_type)) {28896 if (type_is_global_error_set(switch_type)) {
28893 ir_add_error(ira, &instruction->base.base,28897 ir_add_error(ira, &instruction->base.base,
28894 buf_sprintf("else prong required when switching on type 'anyerror'"));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,16 +28954,20 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
28950 return ira->codegen->invalid_inst_gen;28954 return ira->codegen->invalid_inst_gen;
28951 }28955 }
28952 }28956 }
28953 if (!instruction->have_else_prong) {28957
28954 BigInt min_val;28958 BigInt min_val;
28955 eval_min_max_value_int(ira->codegen, switch_type, &min_val, false);28959 eval_min_max_value_int(ira->codegen, switch_type, &min_val, false);
28956 BigInt max_val;28960 BigInt max_val;
28957 eval_min_max_value_int(ira->codegen, switch_type, &max_val, true);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 ir_add_error(ira, &instruction->base.base, buf_sprintf("switch must handle all possibilities"));28964 ir_add_error(ira, &instruction->base.base, buf_sprintf("switch must handle all possibilities"));
28960 return ira->codegen->invalid_inst_gen;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 } else if (switch_type->id == ZigTypeIdBool) {28971 } else if (switch_type->id == ZigTypeIdBool) {
28964 int seenTrue = 0;28972 int seenTrue = 0;
28965 int seenFalse = 0;28973 int seenFalse = 0;
...@@ -28989,11 +28997,17 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,...@@ -28989,11 +28997,17 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
28989 return ira->codegen->invalid_inst_gen;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 ir_add_error(ira, &instruction->base.base, buf_sprintf("switch must handle all possibilities"));29001 ir_add_error(ira, &instruction->base.base, buf_sprintf("switch must handle all possibilities"));
28994 return ira->codegen->invalid_inst_gen;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 ir_add_error(ira, &instruction->base.base,29011 ir_add_error(ira, &instruction->base.base,
28998 buf_sprintf("else prong required when switching on type '%s'", buf_ptr(&switch_type->name)));29012 buf_sprintf("else prong required when switching on type '%s'", buf_ptr(&switch_type->name)));
28999 return ira->codegen->invalid_inst_gen;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,7 +2175,7 @@ static void ir_print_check_switch_prongs(IrPrintSrc *irp, IrInstSrcCheckSwitchPr
2175 fprintf(irp->f, "...");2175 fprintf(irp->f, "...");
2176 ir_print_other_inst_src(irp, instruction->ranges[i].end);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 fprintf(irp->f, ")else:%s", have_else_str);2179 fprintf(irp->f, ")else:%s", have_else_str);
2180}2180}
21812181
test/compile_errors.zig+96
...@@ -509,6 +509,102 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -509,6 +509,102 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
509 "tmp.zig:12:5: error: switch on non-exhaustive enum must include `else` or `_` prong",509 "tmp.zig:12:5: error: switch on non-exhaustive enum must include `else` or `_` prong",
510 });510 });
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
512 cases.addTest("@export with empty name string",608 cases.addTest("@export with empty name string",
513 \\pub export fn entry() void { }609 \\pub export fn entry() void { }
514 \\comptime {610 \\comptime {
test/stage1/behavior/bugs/1111.zig-1
...@@ -7,6 +7,5 @@ test "issue 1111 fixed" {...@@ -7,6 +7,5 @@ test "issue 1111 fixed" {
77
8 switch (v) {8 switch (v) {
9 Foo.Bar => return,9 Foo.Bar => return,
10 else => return,
11 }10 }
12}11}