From fd50696359ec86abd238993930e979433a31db9a Mon Sep 17 00:00:00 2001 From: antlilja Date: Tue, 23 Jun 2020 15:18:28 +0200 Subject: Store else node in IrInstSrcCheckSwitchProngs * Remove have_else_prong (bool) * Add else_prong (AstNode*) --- src/ir.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 635af397c4..44df69aeed 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4274,14 +4274,14 @@ static IrInstGen *ir_build_err_to_int_gen(IrAnalyze *ira, Scope *scope, AstNode static IrInstSrc *ir_build_check_switch_prongs(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *target_value, IrInstSrcCheckSwitchProngsRange *ranges, size_t range_count, - bool have_else_prong, bool have_underscore_prong) + AstNode* else_prong, bool have_underscore_prong) { IrInstSrcCheckSwitchProngs *instruction = ir_build_instruction( irb, scope, source_node); instruction->target_value = target_value; instruction->ranges = ranges; instruction->range_count = range_count; - instruction->have_else_prong = have_else_prong; + instruction->else_prong = else_prong; instruction->have_underscore_prong = have_underscore_prong; ir_ref_instruction(target_value, irb->current_basic_block); @@ -9305,7 +9305,7 @@ static IrInstSrc *ir_gen_switch_expr(IrBuilderSrc *irb, Scope *scope, AstNode *n } IrInstSrc *switch_prongs_void = ir_build_check_switch_prongs(irb, scope, node, target_value, - check_ranges.items, check_ranges.length, else_prong != nullptr, underscore_prong != nullptr); + check_ranges.items, check_ranges.length, else_prong, underscore_prong != nullptr); IrInstSrc *br_instruction; if (cases.length == 0) { @@ -28685,7 +28685,7 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, buf_ptr(enum_field->name))); } } - } else if (!instruction->have_else_prong) { + } else if (instruction->else_prong == nullptr) { if (switch_type->data.enumeration.non_exhaustive) { ir_add_error(ira, &instruction->base.base, buf_sprintf("switch on non-exhaustive enum must include `else` or `_` prong")); @@ -28746,7 +28746,7 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, } field_prev_uses[start_index] = start_value->base.source_node; } - if (!instruction->have_else_prong) { + if (instruction->else_prong == nullptr) { if (type_is_global_error_set(switch_type)) { ir_add_error(ira, &instruction->base.base, buf_sprintf("else prong required when switching on type 'anyerror'")); @@ -28808,7 +28808,7 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, return ira->codegen->invalid_inst_gen; } } - if (!instruction->have_else_prong) { + if (instruction->else_prong == nullptr) { BigInt min_val; eval_min_max_value_int(ira->codegen, switch_type, &min_val, false); BigInt max_val; @@ -28847,11 +28847,11 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, return ira->codegen->invalid_inst_gen; } } - if (((seenTrue < 1) || (seenFalse < 1)) && !instruction->have_else_prong) { + if (((seenTrue < 1) || (seenFalse < 1)) && instruction->else_prong == nullptr) { ir_add_error(ira, &instruction->base.base, buf_sprintf("switch must handle all possibilities")); return ira->codegen->invalid_inst_gen; } - } else if (!instruction->have_else_prong) { + } else if (instruction->else_prong == nullptr) { ir_add_error(ira, &instruction->base.base, buf_sprintf("else prong required when switching on type '%s'", buf_ptr(&switch_type->name))); return ira->codegen->invalid_inst_gen; -- cgit v1.2.3 From dcc406deff0fb4ee3c2cd1f4ff8614e972a8ea7a Mon Sep 17 00:00:00 2001 From: antlilja Date: Wed, 24 Jun 2020 19:12:42 +0200 Subject: Add new error message for unreachable else prongs * Adds error message for types: enum, int and bool * Adds compile error tests --- src/ir.cpp | 20 +++++++++-- test/compile_errors.zig | 96 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 3 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 44df69aeed..8395cf0a3e 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -28700,6 +28700,10 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, buf_ptr(enum_field->name))); } } + } else if(!switch_type->data.enumeration.non_exhaustive && switch_type->data.enumeration.src_field_count == instruction->range_count) { + ir_add_error_node(ira, instruction->else_prong, + buf_sprintf("unreachable else prong, all cases already handled")); + return ira->codegen->invalid_inst_gen; } } else if (switch_type->id == ZigTypeIdErrorSet) { if (!resolve_inferred_error_set(ira->codegen, switch_type, target_value->base.source_node)) { @@ -28808,16 +28812,20 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, return ira->codegen->invalid_inst_gen; } } - if (instruction->else_prong == nullptr) { + BigInt min_val; eval_min_max_value_int(ira->codegen, switch_type, &min_val, false); BigInt max_val; eval_min_max_value_int(ira->codegen, switch_type, &max_val, true); - if (!rangeset_spans(&rs, &min_val, &max_val)) { + bool handles_all_cases = rangeset_spans(&rs, &min_val, &max_val); + if (!handles_all_cases && instruction->else_prong == nullptr) { ir_add_error(ira, &instruction->base.base, buf_sprintf("switch must handle all possibilities")); return ira->codegen->invalid_inst_gen; + } else if(handles_all_cases && instruction->else_prong != nullptr) { + ir_add_error_node(ira, instruction->else_prong, + buf_sprintf("unreachable else prong, all cases already handled")); + return ira->codegen->invalid_inst_gen; } - } } else if (switch_type->id == ZigTypeIdBool) { int seenTrue = 0; int seenFalse = 0; @@ -28851,6 +28859,12 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, ir_add_error(ira, &instruction->base.base, buf_sprintf("switch must handle all possibilities")); return ira->codegen->invalid_inst_gen; } + + if(seenTrue == 1 && seenFalse == 1 && instruction->else_prong != nullptr) { + ir_add_error_node(ira, instruction->else_prong, + buf_sprintf("unreachable else prong, all cases already handled")); + return ira->codegen->invalid_inst_gen; + } } else if (instruction->else_prong == nullptr) { ir_add_error(ira, &instruction->base.base, buf_sprintf("else prong required when switching on type '%s'", buf_ptr(&switch_type->name))); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 3f898cc337..29ff994cd3 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -468,6 +468,102 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:12:5: error: switch on non-exhaustive enum must include `else` or `_` prong", }); + cases.add("switch expression - unreachable else prong (bool)", + \\fn foo(x: bool) void { + \\ switch (x) { + \\ true => {}, + \\ false => {}, + \\ else => {}, + \\ } + \\} + \\export fn entry() usize { return @sizeOf(@TypeOf(foo)); } + , &[_][]const u8{ + "tmp.zig:5:9: error: unreachable else prong, all cases already handled", + }); + + cases.add("switch expression - unreachable else prong (u1)", + \\fn foo(x: u1) void { + \\ switch (x) { + \\ 0 => {}, + \\ 1 => {}, + \\ else => {}, + \\ } + \\} + \\export fn entry() usize { return @sizeOf(@TypeOf(foo)); } + , &[_][]const u8{ + "tmp.zig:5:9: error: unreachable else prong, all cases already handled", + }); + + cases.add("switch expression - unreachable else prong (u2)", + \\fn foo(x: u2) void { + \\ switch (x) { + \\ 0 => {}, + \\ 1 => {}, + \\ 2 => {}, + \\ 3 => {}, + \\ else => {}, + \\ } + \\} + \\export fn entry() usize { return @sizeOf(@TypeOf(foo)); } + , &[_][]const u8{ + "tmp.zig:7:9: error: unreachable else prong, all cases already handled", + }); + + cases.add("switch expression - unreachable else prong (range u8)", + \\fn foo(x: u8) void { + \\ switch (x) { + \\ 0 => {}, + \\ 1 => {}, + \\ 2 => {}, + \\ 3 => {}, + \\ 4...255 => {}, + \\ else => {}, + \\ } + \\} + \\export fn entry() usize { return @sizeOf(@TypeOf(foo)); } + , &[_][]const u8{ + "tmp.zig:8:9: error: unreachable else prong, all cases already handled", + }); + + cases.add("switch expression - unreachable else prong (range i8)", + \\fn foo(x: i8) void { + \\ switch (x) { + \\ -128...0 => {}, + \\ 1 => {}, + \\ 2 => {}, + \\ 3 => {}, + \\ 4...127 => {}, + \\ else => {}, + \\ } + \\} + \\export fn entry() usize { return @sizeOf(@TypeOf(foo)); } + , &[_][]const u8{ + "tmp.zig:8:9: error: unreachable else prong, all cases already handled", + }); + + cases.add("switch expression - unreachable else prong (enum)", + \\const TestEnum = enum{ T1, T2 }; + \\ + \\fn err(x: u8) TestEnum { + \\ switch (x) { + \\ 0 => return TestEnum.T1, + \\ else => return TestEnum.T2, + \\ } + \\} + \\ + \\fn foo(x: u8) void { + \\ switch (err(x)) { + \\ TestEnum.T1 => {}, + \\ TestEnum.T2 => {}, + \\ else => {}, + \\ } + \\} + \\ + \\export fn entry() usize { return @sizeOf(@TypeOf(foo)); } + , &[_][]const u8{ + "tmp.zig:14:9: error: unreachable else prong, all cases already handled", + }); + cases.addTest("@export with empty name string", \\pub export fn entry() void { } \\comptime { -- cgit v1.2.3 From 5f0bde63582c800352b2d11e20bec650bd266a6f Mon Sep 17 00:00:00 2001 From: Vexu Date: Tue, 28 Jul 2020 00:07:15 +0300 Subject: add helpful error note for when function cannot return an error This has caused frequent confusion since it looks like you are handling errors correctly with a try but you forgot to change your return type. --- src/ir.cpp | 27 +++++++++++++++++++++------ test/compile_errors.zig | 22 ++++++++++++++++++++++ 2 files changed, 43 insertions(+), 6 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 4a86f57e3b..15c4e9ec55 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -20603,17 +20603,25 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr, return ira->codegen->invalid_inst_gen; } + ZigType *expected_return_type = result_loc->value->type->data.pointer.child_type; + IrInstGen *dummy_value = ir_const(ira, source_instr, return_type); dummy_value->value->special = ConstValSpecialRuntime; IrInstGen *dummy_result = ir_implicit_cast2(ira, source_instr, - dummy_value, result_loc->value->type->data.pointer.child_type); - if (type_is_invalid(dummy_result->value->type)) + dummy_value, expected_return_type); + if (type_is_invalid(dummy_result->value->type)) { + if ((return_type->id == ZigTypeIdErrorUnion || return_type->id == ZigTypeIdErrorSet) && + expected_return_type->id != ZigTypeIdErrorUnion && expected_return_type->id != ZigTypeIdErrorSet) + { + add_error_note(ira->codegen, ira->new_irb.exec->first_err_trace_msg, + ira->explicit_return_type_source_node, buf_create_from_str("function cannot return an error")); + } return ira->codegen->invalid_inst_gen; - ZigType *res_child_type = result_loc->value->type->data.pointer.child_type; - if (res_child_type == ira->codegen->builtin_types.entry_anytype) { - res_child_type = return_type; } - if (!handle_is_ptr(ira->codegen, res_child_type)) { + if (expected_return_type == ira->codegen->builtin_types.entry_anytype) { + expected_return_type = return_type; + } + if (!handle_is_ptr(ira->codegen, expected_return_type)) { ir_reset_result(call_result_loc); result_loc = nullptr; } @@ -30907,6 +30915,13 @@ static IrInstGen *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstSrcEndEx IrInstGen *store_ptr = ir_analyze_store_ptr(ira, &instruction->base.base, result_loc, value, instruction->result_loc->allow_write_through_const); if (type_is_invalid(store_ptr->value->type)) { + if (instruction->result_loc->id == ResultLocIdReturn && + (value->value->type->id == ZigTypeIdErrorUnion || value->value->type->id == ZigTypeIdErrorSet) && + ira->explicit_return_type->id != ZigTypeIdErrorUnion && ira->explicit_return_type->id != ZigTypeIdErrorSet) + { + add_error_note(ira->codegen, ira->new_irb.exec->first_err_trace_msg, + ira->explicit_return_type_source_node, buf_create_from_str("function cannot return an error")); + } return ira->codegen->invalid_inst_gen; } } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 30b8a3c7ff..9b836ac45a 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -18,6 +18,28 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:2:16: error: sentinels are only allowed on slices and unknown-length pointers", }); + cases.addTest("helpful return type error message", + \\export fn foo() u32 { + \\ return error.Ohno; + \\} + \\fn bar() !u32 { + \\ return error.Ohno; + \\} + \\export fn baz() void { + \\ try bar(); + \\} + \\export fn quux() u32 { + \\ return bar(); + \\} + , &[_][]const u8{ + "tmp.zig:2:17: error: expected type 'u32', found 'error{Ohno}'", + "tmp.zig:1:17: note: function cannot return an error", + "tmp.zig:8:5: error: expected type 'void', found '@TypeOf(bar).ReturnType.ErrorSet'", + "tmp.zig:7:17: note: function cannot return an error", + "tmp.zig:11:15: error: expected type 'u32', found '@TypeOf(bar).ReturnType.ErrorSet!u32'", + "tmp.zig:10:18: note: function cannot return an error", + }); + cases.addTest("int/float conversion to comptime_int/float", \\export fn foo() void { \\ var a: f32 = 2; -- cgit v1.2.3 From 6bba7c702b4482c33c1de7414fb145d0dfc40fcc Mon Sep 17 00:00:00 2001 From: Vexu Date: Sat, 1 Aug 2020 22:46:28 +0300 Subject: add compile error for alignCasting zero sized types --- src/ir.cpp | 13 +++++++++++++ test/compile_errors.zig | 26 ++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 15c4e9ec55..3aadc2557e 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -29098,6 +29098,19 @@ static IrInstGen *ir_align_cast(IrAnalyze *ira, IrInstGen *target, uint32_t alig ZigType *result_type; uint32_t old_align_bytes; + ZigType *actual_ptr = target_type; + if (actual_ptr->id == ZigTypeIdOptional) { + actual_ptr = actual_ptr->data.maybe.child_type; + } else if (is_slice(actual_ptr)) { + actual_ptr = actual_ptr->data.structure.fields[slice_ptr_index]->type_entry; + } + + if (safety_check_on && !type_has_bits(ira->codegen, actual_ptr)) { + ir_add_error(ira, &target->base, + buf_sprintf("cannot adjust alignment of zero sized type '%s'", buf_ptr(&target_type->name))); + return ira->codegen->invalid_inst_gen; + } + if (target_type->id == ZigTypeIdPointer) { result_type = adjust_ptr_align(ira->codegen, target_type, align_bytes); if ((err = resolve_ptr_align(ira, target_type, &old_align_bytes))) diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 9b836ac45a..6b231a323d 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2,6 +2,32 @@ const tests = @import("tests.zig"); const std = @import("std"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest("@alignCast of zero sized types", + \\export fn foo() void { + \\ const a: *void = undefined; + \\ _ = @alignCast(2, a); + \\} + \\export fn bar() void { + \\ const a: ?*void = undefined; + \\ _ = @alignCast(2, a); + \\} + \\export fn baz() void { + \\ const a: []void = undefined; + \\ _ = @alignCast(2, a); + \\} + \\export fn qux() void { + \\ const a = struct { + \\ fn a(comptime b: u32) void {} + \\ }.a; + \\ _ = @alignCast(2, a); + \\} + , &[_][]const u8{ + "tmp.zig:3:23: error: cannot adjust alignment of zero sized type '*void'", + "tmp.zig:7:23: error: cannot adjust alignment of zero sized type '?*void'", + "tmp.zig:11:23: error: cannot adjust alignment of zero sized type '[]void'", + "tmp.zig:17:23: error: cannot adjust alignment of zero sized type 'fn(u32) anytype'", + }); + cases.addTest("invalid pointer with @Type", \\export fn entry() void { \\ _ = @Type(.{ .Pointer = .{ -- cgit v1.2.3