authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-05-07 13:40:35-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-05-07 13:40:35-04:00
log7261cd19b78367d78f758f7ade370efbc3e25237
tree750ec114dd9c6c15552796001e95d2f355b4f7ae
parentdc2df155285576b8da621fbffac451c036af0ed0

detect duplicate switch value even when else prong present

closes #43

4 files changed, 47 insertions(+), 18 deletions(-)

src/all_types.hpp+1
...@@ -2471,6 +2471,7 @@ struct IrInstructionCheckSwitchProngs {...@@ -2471,6 +2471,7 @@ struct IrInstructionCheckSwitchProngs {
2471 IrInstruction *target_value;2471 IrInstruction *target_value;
2472 IrInstructionCheckSwitchProngsRange *ranges;2472 IrInstructionCheckSwitchProngsRange *ranges;
2473 size_t range_count;2473 size_t range_count;
2474 bool have_else_prong;
2474};2475};
24752476
2476struct IrInstructionCheckStatementIsVoid {2477struct IrInstructionCheckStatementIsVoid {
src/ir.cpp+22-17
...@@ -2015,13 +2015,15 @@ static IrInstruction *ir_build_err_to_int(IrBuilder *irb, Scope *scope, AstNode...@@ -2015,13 +2015,15 @@ static IrInstruction *ir_build_err_to_int(IrBuilder *irb, Scope *scope, AstNode
2015}2015}
20162016
2017static IrInstruction *ir_build_check_switch_prongs(IrBuilder *irb, Scope *scope, AstNode *source_node,2017static IrInstruction *ir_build_check_switch_prongs(IrBuilder *irb, Scope *scope, AstNode *source_node,
2018 IrInstruction *target_value, IrInstructionCheckSwitchProngsRange *ranges, size_t range_count)2018 IrInstruction *target_value, IrInstructionCheckSwitchProngsRange *ranges, size_t range_count,
2019 bool have_else_prong)
2019{2020{
2020 IrInstructionCheckSwitchProngs *instruction = ir_build_instruction<IrInstructionCheckSwitchProngs>(2021 IrInstructionCheckSwitchProngs *instruction = ir_build_instruction<IrInstructionCheckSwitchProngs>(
2021 irb, scope, source_node);2022 irb, scope, source_node);
2022 instruction->target_value = target_value;2023 instruction->target_value = target_value;
2023 instruction->ranges = ranges;2024 instruction->ranges = ranges;
2024 instruction->range_count = range_count;2025 instruction->range_count = range_count;
2026 instruction->have_else_prong = have_else_prong;
20252027
2026 ir_ref_instruction(target_value, irb->current_basic_block);2028 ir_ref_instruction(target_value, irb->current_basic_block);
2027 for (size_t i = 0; i < range_count; i += 1) {2029 for (size_t i = 0; i < range_count; i += 1) {
...@@ -5542,9 +5544,8 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *...@@ -5542,9 +5544,8 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
5542 }5544 }
5543 }5545 }
55445546
5545 if (!else_prong) {5547 ir_build_check_switch_prongs(irb, scope, node, target_value, check_ranges.items, check_ranges.length,
5546 ir_build_check_switch_prongs(irb, scope, node, target_value, check_ranges.items, check_ranges.length);5548 else_prong != nullptr);
5547 }
55485549
5549 if (cases.length == 0) {5550 if (cases.length == 0) {
5550 ir_build_br(irb, scope, node, else_block, is_comptime);5551 ir_build_br(irb, scope, node, else_block, is_comptime);
...@@ -13019,11 +13020,13 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira...@@ -13019,11 +13020,13 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
13019 field_prev_uses[field_index] = start_value->source_node;13020 field_prev_uses[field_index] = start_value->source_node;
13020 }13021 }
13021 }13022 }
13022 for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) {13023 if (!instruction->have_else_prong) {
13023 if (field_prev_uses[i] == nullptr) {13024 for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) {
13024 ir_add_error(ira, &instruction->base,13025 if (field_prev_uses[i] == nullptr) {
13025 buf_sprintf("enumeration value '%s.%s' not handled in switch", buf_ptr(&enum_type->name),13026 ir_add_error(ira, &instruction->base,
13026 buf_ptr(enum_type->data.enumeration.fields[i].name)));13027 buf_sprintf("enumeration value '%s.%s' not handled in switch", buf_ptr(&enum_type->name),
13028 buf_ptr(enum_type->data.enumeration.fields[i].name)));
13029 }
13027 }13030 }
13028 }13031 }
13029 } else if (switch_type->id == TypeTableEntryIdInt) {13032 } else if (switch_type->id == TypeTableEntryIdInt) {
...@@ -13055,15 +13058,17 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira...@@ -13055,15 +13058,17 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
13055 return ira->codegen->builtin_types.entry_invalid;13058 return ira->codegen->builtin_types.entry_invalid;
13056 }13059 }
13057 }13060 }
13058 BigNum min_val;13061 if (!instruction->have_else_prong) {
13059 eval_min_max_value_int(ira->codegen, switch_type, &min_val, false);13062 BigNum min_val;
13060 BigNum max_val;13063 eval_min_max_value_int(ira->codegen, switch_type, &min_val, false);
13061 eval_min_max_value_int(ira->codegen, switch_type, &max_val, true);13064 BigNum max_val;
13062 if (!rangeset_spans(&rs, &min_val, &max_val)) {13065 eval_min_max_value_int(ira->codegen, switch_type, &max_val, true);
13063 ir_add_error(ira, &instruction->base, buf_sprintf("switch must handle all possibilities"));13066 if (!rangeset_spans(&rs, &min_val, &max_val)) {
13064 return ira->codegen->builtin_types.entry_invalid;13067 ir_add_error(ira, &instruction->base, buf_sprintf("switch must handle all possibilities"));
13068 return ira->codegen->builtin_types.entry_invalid;
13069 }
13065 }13070 }
13066 } else {13071 } else if (!instruction->have_else_prong) {
13067 ir_add_error(ira, &instruction->base,13072 ir_add_error(ira, &instruction->base,
13068 buf_sprintf("else prong required when switching on type '%s'", buf_ptr(&switch_type->name)));13073 buf_sprintf("else prong required when switching on type '%s'", buf_ptr(&switch_type->name)));
13069 return ira->codegen->builtin_types.entry_invalid;13074 return ira->codegen->builtin_types.entry_invalid;
src/ir_print.cpp+2-1
...@@ -807,7 +807,8 @@ static void ir_print_check_switch_prongs(IrPrint *irp, IrInstructionCheckSwitchP...@@ -807,7 +807,8 @@ static void ir_print_check_switch_prongs(IrPrint *irp, IrInstructionCheckSwitchP
807 fprintf(irp->f, "...");807 fprintf(irp->f, "...");
808 ir_print_other_instruction(irp, instruction->ranges[i].end);808 ir_print_other_instruction(irp, instruction->ranges[i].end);
809 }809 }
810 fprintf(irp->f, ")");810 const char *have_else_str = instruction->have_else_prong ? "yes" : "no";
811 fprintf(irp->f, ")else:%s", have_else_str);
811}812}
812813
813static void ir_print_check_statement_is_void(IrPrint *irp, IrInstructionCheckStatementIsVoid *instruction) {814static void ir_print_check_statement_is_void(IrPrint *irp, IrInstructionCheckStatementIsVoid *instruction) {
test/compile_errors.zig+22
...@@ -581,6 +581,28 @@ pub fn addCases(cases: &tests.CompileErrorContext) {...@@ -581,6 +581,28 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
581 , ".tmp_source.zig:13:15: error: duplicate switch value",581 , ".tmp_source.zig:13:15: error: duplicate switch value",
582 ".tmp_source.zig:10:15: note: other value is here");582 ".tmp_source.zig:10:15: note: other value is here");
583583
584 cases.add("switch expression - duplicate enumeration prong when else present",
585 \\const Number = enum {
586 \\ One,
587 \\ Two,
588 \\ Three,
589 \\ Four,
590 \\};
591 \\fn f(n: Number) -> i32 {
592 \\ switch (n) {
593 \\ Number.One => 1,
594 \\ Number.Two => 2,
595 \\ Number.Three => i32(3),
596 \\ Number.Four => 4,
597 \\ Number.Two => 2,
598 \\ else => 10,
599 \\ }
600 \\}
601 \\
602 \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
603 , ".tmp_source.zig:13:15: error: duplicate switch value",
604 ".tmp_source.zig:10:15: note: other value is here");
605
584 cases.add("switch expression - multiple else prongs",606 cases.add("switch expression - multiple else prongs",
585 \\fn f(x: u32) {607 \\fn f(x: u32) {
586 \\ const value: bool = switch (x) {608 \\ const value: bool = switch (x) {