From 64e9d8e805538b430f1812d627f6f395f0b25b70 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Tue, 21 Apr 2026 14:57:14 +0300 Subject: [PATCH] cgen: fix hot reload failure when using time.now() in interpolation (fixes #19456) --- vlib/v/gen/c/str_intp.v | 36 +++++++++++++++++-- ...d_string_interpolation_codegen.c.must_have | 2 ++ ...ive_shared_string_interpolation_codegen.vv | 14 ++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 vlib/v/gen/c/testdata/live_shared_string_interpolation_codegen.c.must_have create mode 100644 vlib/v/gen/c/testdata/live_shared_string_interpolation_codegen.vv diff --git a/vlib/v/gen/c/str_intp.v b/vlib/v/gen/c/str_intp.v index 455bfbec0..720bde9e9 100644 --- a/vlib/v/gen/c/str_intp.v +++ b/vlib/v/gen/c/str_intp.v @@ -454,6 +454,9 @@ fn (mut g Gen) str_val(node ast.StringInterLiteral, i int, fmts []u8) { g.inside_opt_or_res = old_inside_opt_or_res g.write('.data))') } else { + if g.gen_windows_liveshared_string_tmp(expr, exp_typ) { + return + } g.gen_expr_to_string(expr, exp_typ) } } else if typ.is_number() || typ.is_pointer() || fmt == `d` { @@ -783,7 +786,9 @@ fn (mut g Gen) gen_simple_string_inter_literal(node ast.StringInterLiteral, fmts } } if node.exprs.len == 1 && node.vals.len == 2 && node.vals[0].len == 0 && node.vals[1].len == 0 { - g.gen_expr_to_string(node.exprs[0], node.expr_types[0]) + if !g.gen_windows_liveshared_string_tmp(node.exprs[0], node.expr_types[0]) { + g.gen_expr_to_string(node.exprs[0], node.expr_types[0]) + } return true } mut part_count := 0 @@ -815,10 +820,37 @@ fn (mut g Gen) gen_simple_string_inter_literal(node ast.StringInterLiteral, fmts if written_parts > 0 { g.write(', ') } - g.gen_expr_to_string(node.exprs[i], node.expr_types[i]) + if !g.gen_windows_liveshared_string_tmp(node.exprs[i], node.expr_types[i]) { + g.gen_expr_to_string(node.exprs[i], node.expr_types[i]) + } written_parts++ } } g.write('}))') return true } + +fn (g &Gen) should_materialize_windows_liveshared_string(expr ast.Expr, typ ast.Type) bool { + if g.pref.os != .windows || !g.pref.is_liveshared || g.inside_const { + return false + } + // The live shared DLL path on Windows is sensitive to nested string-returning + // expressions inside interpolation compound literals, so lower them via temps. + if typ == ast.string_type { + return expr !is ast.Ident && expr !is ast.StringLiteral && expr !is ast.SelectorExpr + && expr !is ast.ComptimeSelector + } + return true +} + +fn (mut g Gen) gen_windows_liveshared_string_tmp(expr ast.Expr, typ ast.Type) bool { + if !g.should_materialize_windows_liveshared_string(expr, typ) { + return false + } + past := g.past_tmp_var_new() + g.write('string ${past.tmp_var} = ') + g.gen_expr_to_string(expr, typ) + g.writeln(';') + g.past_tmp_var_done(past) + return true +} diff --git a/vlib/v/gen/c/testdata/live_shared_string_interpolation_codegen.c.must_have b/vlib/v/gen/c/testdata/live_shared_string_interpolation_codegen.c.must_have new file mode 100644 index 000000000..002524cf4 --- /dev/null +++ b/vlib/v/gen/c/testdata/live_shared_string_interpolation_codegen.c.must_have @@ -0,0 +1,2 @@ +string _t1 = time__Time_str(t); +builtin__println(builtin__string_plus_many(2, _MOV((string[2]){_S("Time: "),_t1}))); diff --git a/vlib/v/gen/c/testdata/live_shared_string_interpolation_codegen.vv b/vlib/v/gen/c/testdata/live_shared_string_interpolation_codegen.vv new file mode 100644 index 000000000..d892709bc --- /dev/null +++ b/vlib/v/gen/c/testdata/live_shared_string_interpolation_codegen.vv @@ -0,0 +1,14 @@ +// vtest vflags: -os windows -sharedlive -shared +module main + +import time + +@[live] +fn print_message2() { + t := time.now() + println('Time: ${t}') +} + +fn main() { + print_message2() +} -- 2.39.5