diff --git a/lib/std/encoding/csv.c3 b/lib/std/encoding/csv.c3 index 407695ca5..55d09af4d 100644 --- a/lib/std/encoding/csv.c3 +++ b/lib/std/encoding/csv.c3 @@ -78,7 +78,7 @@ fn void! CsvReader.skip_row(self) @maydiscard }; } -macro CsvReader.@each_row(self, int rows = int.max; @body(String[] row)) +macro void! CsvReader.@each_row(self, int rows = int.max; @body(String[] row)) @maydiscard { InStream stream = self.stream; String sep = self.separator; diff --git a/releasenotes.md b/releasenotes.md index ecd85081e..76b90e959 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -43,6 +43,7 @@ - Fix error where panic would not properly stop the program when stacktrace couldn't be printed #1751. - Macros with default arguments to `&`, `#` and type parameters didn't work as expected. #1754. - `net::poll()` with negative timeout behaved incorrectly. +- Return type inference bugs with macros #1757 ### Stdlib changes - Increase BitWriter.write_bits limit up to 32 bits. diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index aa44bfd80..3cd1cbcdf 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -6591,6 +6591,10 @@ static inline void llvm_emit_macro_block(GenContext *c, BEValue *be_value, Expr c->debug.block_stack = &updated; llvm_emit_return_block(c, be_value, expr->type, expr->macro_block.first_stmt, expr->macro_block.block_exit); + if (!c->current_block && !expr->macro_block.is_noreturn) + { + llvm_emit_block(c, llvm_basic_block_new(c, "after_macro")); + } bool is_unreachable = expr->macro_block.is_noreturn && c->current_block; if (is_unreachable) { diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 16795d10c..48c3e5a1b 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -2324,6 +2324,7 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s { rtype = context_unify_returns(¯o_context); if (!rtype) goto EXIT_FAIL; + optional_return = type_is_optional(rtype); } // Handle the implicit return. diff --git a/test/test_suite/assert/unreachable_in_macro.c3t b/test/test_suite/assert/unreachable_in_macro.c3t new file mode 100644 index 000000000..d4025c7bf --- /dev/null +++ b/test/test_suite/assert/unreachable_in_macro.c3t @@ -0,0 +1,99 @@ +// #target: windows-x64 +module test; +import std; +fn int main() +{ + if (catch test()) + { + io::printn("Hello"); + } + (void)test(); + return 0; +} + +fault Bob +{ + ABC +} + +macro test() +{ + if (false) return; + return Bob.ABC?; + unreachable(); +} + +/* #expect: test.ll + +define i32 @main() #0 { +entry: + %temp_err = alloca i64, align 8 + %len = alloca i64, align 8 + %error_var = alloca i64, align 8 + %retparam = alloca i64, align 8 + %indirectarg = alloca %"char[]", align 8 + %error_var2 = alloca i64, align 8 + %error_var8 = alloca i64, align 8 + br label %testblock +testblock: ; preds = %entry + br label %if.exit +if.exit: ; preds = %testblock + store i64 ptrtoint (ptr @"test.Bob$ABC" to i64), ptr %temp_err, align 8 + br label %end_block +end_block: ; preds = %if.exit + %0 = load i64, ptr %temp_err, align 8 + %i2b = icmp ne i64 %0, 0 + br i1 %i2b, label %if.then, label %if.exit14 +if.then: ; preds = %end_block + %1 = call ptr @std.io.stdout() + store %"char[]" { ptr @.str, i64 5 }, ptr %indirectarg, align 8 + %2 = call i64 @std.io.File.write(ptr %retparam, ptr %1, ptr align 8 %indirectarg) + %not_err = icmp eq i64 %2, 0 + %3 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) + br i1 %3, label %after_check, label %assign_optional +assign_optional: ; preds = %if.then + store i64 %2, ptr %error_var, align 8 + br label %guard_block +after_check: ; preds = %if.then + br label %noerr_block +guard_block: ; preds = %assign_optional + br label %voiderr +noerr_block: ; preds = %after_check + %4 = load i64, ptr %retparam, align 8 + store i64 %4, ptr %len, align 8 + %5 = call i64 @std.io.File.write_byte(ptr %1, i8 10) + %not_err3 = icmp eq i64 %5, 0 + %6 = call i1 @llvm.expect.i1(i1 %not_err3, i1 true) + br i1 %6, label %after_check5, label %assign_optional4 +assign_optional4: ; preds = %noerr_block + store i64 %5, ptr %error_var2, align 8 + br label %guard_block6 +after_check5: ; preds = %noerr_block + br label %noerr_block7 +guard_block6: ; preds = %assign_optional4 + br label %voiderr +noerr_block7: ; preds = %after_check5 + %7 = call i64 @std.io.File.flush(ptr %1) + %not_err9 = icmp eq i64 %7, 0 + %8 = call i1 @llvm.expect.i1(i1 %not_err9, i1 true) + br i1 %8, label %after_check11, label %assign_optional10 +assign_optional10: ; preds = %noerr_block7 + store i64 %7, ptr %error_var8, align 8 + br label %guard_block12 +after_check11: ; preds = %noerr_block7 + br label %noerr_block13 +guard_block12: ; preds = %assign_optional10 + br label %voiderr +noerr_block13: ; preds = %after_check11 + %9 = load i64, ptr %len, align 8 + %add = add i64 %9, 1 + br label %voiderr +voiderr: ; preds = %noerr_block13, %guard_block12, %guard_block6, %guard_block + br label %if.exit14 +if.exit14: ; preds = %voiderr, %end_block + br label %if.exit15 +if.exit15: ; preds = %if.exit14 + br label %after_macro +after_macro: ; preds = %if.exit15 + ret i32 0 +}