From 0bc546595de91d8a5d6665fde2e925b0188d59ae Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sat, 26 Jul 2025 02:03:02 +0200 Subject: [PATCH] - Using @noreturn in a trailing body macro would not work properly #2326. - Bug when reporting error in a macro return would crash the compiler #2326. - Short body return expression would not have the correct span. --- releasenotes.md | 3 +++ src/compiler/parse_stmt.c | 4 +++- src/compiler/sema_expr.c | 2 +- src/compiler/sema_stmts.c | 7 +++++++ test/test_suite/macros/macro_noreturn1.c3 | 9 +++++++++ 5 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 test/test_suite/macros/macro_noreturn1.c3 diff --git a/releasenotes.md b/releasenotes.md index bae8bec99..37cf65476 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -74,6 +74,9 @@ - Regression: Chaining an optional together with contracts could in some cases lose the optional. - `char[*] b = *(char[*]*)&a;` would crash the compiler if `a` was a slice. #2320 - Implicitly cast const int expressions would sometimes not be detected as compile time const. +- Using @noreturn in a short body macro would not work properly #2326. +- Bug when reporting error in a macro return would crash the compiler #2326. +- Short body return expression would not have the correct span. ### Stdlib changes - Improve contract for readline. #2280 diff --git a/src/compiler/parse_stmt.c b/src/compiler/parse_stmt.c index 573280781..0b40e3bb4 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -1077,6 +1077,7 @@ static inline Ast *parse_return_stmt(ParseContext *c) if (!tok_is(c, TOKEN_EOS)) { ASSIGN_EXPR_OR_RET(ast->return_stmt.expr, parse_expr(c), poisoned_ast); + RANGE_EXTEND_PREV(ast); } CONSUME_EOS_OR_RET(poisoned_ast); return ast; @@ -1532,6 +1533,7 @@ Ast *parse_short_body(ParseContext *c, TypeInfoId return_type, bool is_regular_f TypeInfo *rtype = return_type ? type_infoptr(return_type) : NULL; bool is_void_return = rtype && rtype->resolve_status == RESOLVE_DONE && rtype->type->type_kind == TYPE_VOID; ASSIGN_EXPR_OR_RET(Expr *expr, parse_expr(c), poisoned_ast); + ret->span = expr->span; if (expr->expr_kind == EXPR_CALL && expr->call_expr.macro_body) { ret->ast_kind = AST_EXPR_STMT; @@ -1548,7 +1550,7 @@ Ast *parse_short_body(ParseContext *c, TypeInfoId return_type, bool is_regular_f } ret->return_stmt.expr = expr; END:; - RANGE_EXTEND_PREV(ast); + if (is_regular_fn) { CONSUME_EOS_OR_RET(poisoned_ast); diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index f2258fa96..e622469bd 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -2809,7 +2809,7 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s } else if (is_no_return) { - SEMA_ERROR(context->block_returns[0], "Return used despite macro being marked '@noreturn'."); + SEMA_ERROR(macro_context.block_returns[0], "Return used despite macro being marked '@noreturn'."); goto EXIT_FAIL; } diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 40a4fabb5..e663ea9e8 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -575,6 +575,13 @@ static inline bool sema_analyse_block_exit_stmt(SemaContext *context, Ast *state if (!sema_analyse_expr(context, ret_expr)) return false; } if (!sema_check_return_matches_opt_returns(context, ret_expr)) return false; + if (ret_expr->expr_kind == EXPR_CALL && ret_expr->call_expr.no_return) + { + statement->ast_kind = AST_EXPR_STMT; + statement->expr_stmt = ret_expr; + sema_inline_return_defers(context, statement, context->block_return_defer); + return true; + } } else { diff --git a/test/test_suite/macros/macro_noreturn1.c3 b/test/test_suite/macros/macro_noreturn1.c3 new file mode 100644 index 000000000..360dd0de9 --- /dev/null +++ b/test/test_suite/macros/macro_noreturn1.c3 @@ -0,0 +1,9 @@ +import std; +macro @gogo_abort() @noreturn => os::exit(1); + +fn void main() +{ + File? f = file::open("/tmp/ooo", "w"); + if (catch err = f) @gogo_abort(); + File g = f; +} \ No newline at end of file