From af91f350176871de853df76a4222ba350edce71c Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Tue, 15 Jul 2025 17:13:10 +0200 Subject: [PATCH] Fix stringify of $vaexpr #2301. --- releasenotes.md | 1 + src/compiler/parse_expr.c | 2 +- src/compiler/sema_expr.c | 29 ++++++++---- .../compile_time/stringify_vaexp.c3t | 47 +++++++++++++++++++ 4 files changed, 70 insertions(+), 9 deletions(-) create mode 100644 test/test_suite/compile_time/stringify_vaexp.c3t diff --git a/releasenotes.md b/releasenotes.md index 08fdc93cd..3abee118c 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -51,6 +51,7 @@ - Fixed bug splatting constants into constants. - Resize bug when resizing memory down in ArenaAllocator, DynamicArenaAllocator, BackedArenaAllocator. - Error message for missing arg incorrect for methods with zero args #2296. +- Fix stringify of $vaexpr #2301. ### Stdlib changes - Improve contract for readline. #2280 diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index a7144454c..0a580a1db 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -659,7 +659,7 @@ static Expr *parse_ct_stringify(ParseContext *c, Expr *left, SourceSpan lhs_star ASSIGN_EXPR_OR_RET(Expr *inner, parse_expr(c), poisoned_expr); const char *end = c->lexer.lexing_start - 1; CONSUME_OR_RET(TOKEN_RPAREN, poisoned_expr); - if (inner->expr_kind == EXPR_HASH_IDENT) + if (inner->expr_kind == EXPR_HASH_IDENT || (inner->expr_kind == EXPR_CT_ARG && inner->ct_arg_expr.type == TOKEN_CT_VAEXPR)) { Expr *expr = expr_new(EXPR_STRINGIFY, start_span); expr->inner_expr = inner; diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index d2ad30c39..92524168d 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -10591,18 +10591,31 @@ static inline bool sema_expr_analyse_ct_stringify(SemaContext *context, Expr *ex { Expr *inner = expr->inner_expr; // Only hash ident style stringify reaches here. - ASSERT_SPAN(expr, inner->expr_kind == EXPR_HASH_IDENT); while (true) { - Decl *decl = sema_resolve_symbol(context, inner->ct_ident_expr.identifier, NULL, inner->span); - if (!decl) return false; - inner = decl->var.init_expr; - while (inner->expr_kind == EXPR_OTHER_CONTEXT) + switch (inner->expr_kind) { - context = inner->expr_other_context.context; - inner = inner->expr_other_context.inner; + case EXPR_CT_ARG: + { + ASSIGN_EXPR_OR_RET(Expr *arg_expr, sema_expr_analyse_ct_arg_index(context, exprptr(inner->ct_arg_expr.arg), NULL), false); + inner = arg_expr; + continue; + } + case EXPR_OTHER_CONTEXT: + context = inner->expr_other_context.context; + inner = inner->expr_other_context.inner; + continue; + case EXPR_HASH_IDENT: + { + Decl *decl = sema_resolve_symbol(context, inner->ct_ident_expr.identifier, NULL, inner->span); + if (!decl) return false; + inner = decl->var.init_expr; + continue; + } + default: + break; } - if (inner->expr_kind != EXPR_HASH_IDENT) break; + break; } const char *desc = span_to_string(inner->span); if (!desc) diff --git a/test/test_suite/compile_time/stringify_vaexp.c3t b/test/test_suite/compile_time/stringify_vaexp.c3t new file mode 100644 index 000000000..41ee4b04a --- /dev/null +++ b/test/test_suite/compile_time/stringify_vaexp.c3t @@ -0,0 +1,47 @@ +// #target: macos-x64 +module test; +import std::io; + +fn int main(String[] args) +{ + String a = @foo1(args); + String b = @foo2(args); + String c = @foo3(args); + return 0; +} + +macro @foo1(#expr) +{ + return $stringify(#expr); +} + +macro @foo2(...) +{ + return $stringify($vaexpr[0]); +} + +macro @foo3(#expr) +{ + return @foo2(#expr); +} + +/* #expect: test.ll + +@.str = private unnamed_addr constant [5 x i8] c"args\00", align 1 +@.str.1 = private unnamed_addr constant [5 x i8] c"args\00", align 1 +@.str.2 = private unnamed_addr constant [5 x i8] c"args\00", align 1 + +define i32 @test.main(ptr %0, i64 %1) #0 { +entry: + %args = alloca %"char[][]", align 8 + %a = alloca %"char[]", align 8 + %b = alloca %"char[]", align 8 + %c = alloca %"char[]", align 8 + store ptr %0, ptr %args, align 8 + %ptradd = getelementptr inbounds i8, ptr %args, i64 8 + store i64 %1, ptr %ptradd, align 8 + store %"char[]" { ptr @.str, i64 4 }, ptr %a, align 8 + store %"char[]" { ptr @.str.1, i64 4 }, ptr %b, align 8 + store %"char[]" { ptr @.str.2, i64 4 }, ptr %c, align 8 + ret i32 0 +}