From 070b13c81c20fecbc4f13ddadc103bb4f3e53206 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Tue, 16 Dec 2025 21:48:35 +0100 Subject: [PATCH] More fixes to $$LINE --- releasenotes.md | 2 +- src/compiler/sema_expr.c | 21 +++++--- src/compiler/sema_stmts.c | 1 - test/test_suite/builtins/builtin_line.c3t | 61 +++++++++++++++++++++++ 4 files changed, 76 insertions(+), 9 deletions(-) create mode 100644 test/test_suite/builtins/builtin_line.c3t diff --git a/releasenotes.md b/releasenotes.md index ebf0cbebc..370660cb8 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -20,7 +20,7 @@ - `$defined(foo())` now correctly errors if `foo()` would require a path. - `@if($defined((char*){}.foo()))` does not error if `foo` is missing. - Hard limit of 127 characters for identifiers. -- `$$LINE` would sometimes incorrectly be constant. +- `$$LINE` would sometimes yield the incorrect format. - Fix error message when a method has the wrong type for the first argument. ### Stdlib changes diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 41b0a9bbc..e1794ae03 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -1689,16 +1689,20 @@ INLINE bool sema_set_default_argument(SemaContext *context, CalledDecl *callee, { SemaContext default_context; SemaContext *new_context = context_transform_for_eval(context, &default_context, param->unit); + ContextSwitchState switch_state = context_switch_state_push(context, new_context); + InliningSpan inlined_at; + if (!new_context->inlined_at) + { + inlined_at = (InliningSpan) { .span = call->span }; + new_context->inlined_at = &inlined_at; + } bool success; SCOPE_START - uint32_t line = new_context->original_inline_line; - new_context->original_inline_line = context->original_inline_line ? context->original_inline_line - : call->span.row; new_context->original_module = context->original_module; success = sema_analyse_parameter(new_context, arg, param, callee->definition, optional, no_match_ref, callee->macro, false); - new_context->original_inline_line = line; SCOPE_END; + context_switch_stat_pop(new_context, switch_state); sema_context_destroy(&default_context); if (no_match_ref && *no_match_ref) return true; if (!success) RETURN_NOTE_FUNC_DEFINITION; @@ -2847,7 +2851,6 @@ static inline bool sema_expr_setup_call_analysis(SemaContext *context, CalledDec } macro_context->macro_has_vaargs = callee->macro && callee->signature->variadic == VARIADIC_RAW; macro_context->macro_varargs = macro_context->macro_has_vaargs ? call_expr->call_expr.varargs : NULL; - macro_context->original_inline_line = context->original_inline_line ? context->original_inline_line : call_expr->span.row; macro_context->original_module = context->original_module ? context->original_module : context->compilation_unit->module; macro_context->macro_params = params; @@ -9951,15 +9954,19 @@ static inline bool sema_expr_analyse_compiler_const(SemaContext *context, Expr * } return true; case BUILTIN_DEF_LINE: - if (context->original_inline_line) + { + InliningSpan *span = context->inlined_at; + if (span) { - expr_rewrite_const_int(expr, type_isz, context->original_inline_line); + while (span->prev) span = span->prev; + expr_rewrite_const_int(expr, type_isz, span->span.row); } else { expr_rewrite_const_int(expr, type_isz, expr->span.row); } return true; + } case BUILTIN_DEF_LINE_RAW: expr_rewrite_const_int(expr, type_isz, expr->span.row); return true; diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 1952bea29..6e7b2636d 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -3424,7 +3424,6 @@ bool sema_analyse_function_body(SemaContext *context, Decl *func) ASSERT_SPAN(func, prototype); // Set up the context for analysis - context->original_inline_line = 0; context->original_module = NULL; context->call_env = (CallEnv) { .current_function = func, diff --git a/test/test_suite/builtins/builtin_line.c3t b/test/test_suite/builtins/builtin_line.c3t new file mode 100644 index 000000000..2679c2127 --- /dev/null +++ b/test/test_suite/builtins/builtin_line.c3t @@ -0,0 +1,61 @@ +// #target: macos-aarch64 +module test; +import std, test2; + +struct UJsonReader +{ + String last_error_file; + String last_error_func; + int last_error_line; +} + +faultdef INVALID_KIND; + +fn void? UJsonReader.dict(&self, String file = $$FILE, String func = $$FUNC, int line = $$LINE) +{ + self.last_error_file = file; + self.last_error_func = func; + self.last_error_line = line; + return INVALID_KIND?; +} + +fn int main() +{ + UJsonReader r; + int a = $$LINE; + @test(r.dict()); + (void)r.dict(); + return r.last_error_line; +} +module test2; +macro void @test(#expr) @builtin +{ + (void)#expr; +} + +/* #expect: test.ll + +define i32 @main() #0 { +entry: + %r = alloca %UJsonReader, align 8 + %a = alloca i32, align 4 + %taddr = alloca %"char[]", align 8 + %taddr1 = alloca %"char[]", align 8 + %taddr2 = alloca %"char[]", align 8 + %taddr3 = alloca %"char[]", align 8 + call void @llvm.memset.p0.i64(ptr align 8 %r, i8 0, i64 40, i1 false) + store i32 24, ptr %a, align 4 + store %"char[]" { ptr @.str, i64 15 }, ptr %taddr, align 8 + %0 = load [2 x i64], ptr %taddr, align 8 + store %"char[]" { ptr @.str.1, i64 4 }, ptr %taddr1, align 8 + %1 = load [2 x i64], ptr %taddr1, align 8 + %2 = call i64 @test.UJsonReader.dict(ptr %r, [2 x i64] %0, [2 x i64] %1, i32 25) + store %"char[]" { ptr @.str.2, i64 15 }, ptr %taddr2, align 8 + %3 = load [2 x i64], ptr %taddr2, align 8 + store %"char[]" { ptr @.str.3, i64 4 }, ptr %taddr3, align 8 + %4 = load [2 x i64], ptr %taddr3, align 8 + %5 = call i64 @test.UJsonReader.dict(ptr %r, [2 x i64] %3, [2 x i64] %4, i32 26) + %ptradd = getelementptr inbounds i8, ptr %r, i64 32 + %6 = load i32, ptr %ptradd, align 8 + ret i32 %6 +}