@@ -992,7 +992,14 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
992992 } else {
993993 is_option_unwrapped := val is ast.Ident && val.or_expr.kind != .absent
994994 is_option_auto_heap := is_auto_heap && is_option_unwrapped
995- if is_auto_heap && ! is_fn_var {
995+ // For large structs (with large fixed arrays), avoid stack-allocated
996+ // compound literals which can cause stack overflow. Use vcalloc directly.
997+ mut is_large_struct_heap := false
998+ if is_auto_heap && ! is_fn_var && val is ast.StructInit
999+ && g.struct_has_large_fixed_array (val.typ) {
1000+ is_large_struct_heap = true
1001+ }
1002+ if is_auto_heap && ! is_fn_var && ! is_large_struct_heap {
9961003 if aligned != 0 {
9971004 g.write ('HEAP_align(${styp }, (' )
9981005 } else {
@@ -1037,14 +1044,53 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
10371044 tmp_var := g.expr_with_var (val, var_type, false )
10381045 g.fixed_array_var_init (tmp_var, false , unaliased_right_sym.info.elem_type,
10391046 unaliased_right_sym.info.size)
1047+ } else if is_large_struct_heap && val is ast.StructInit {
1048+ // For large structs, use vcalloc directly to avoid stack overflow
1049+ // from compound literals on the stack
1050+ tmp_var := g.new_tmp_var ()
1051+ stmt_str := g.go_before_last_stmt ()
1052+ g.empty_line = true
1053+ g.writeln ('${styp }* ${tmp_var } = (${styp }*)builtin__vcalloc(sizeof(${styp }));' )
1054+ // Initialize non-zero fields
1055+ val_sym := g.table.final_sym (val.typ)
1056+ if val_sym.info is ast.Struct {
1057+ for init_field in val.init_fields {
1058+ if init_field.typ == 0 {
1059+ continue
1060+ }
1061+ field_name := c_name (init_field.name)
1062+ g.write ('${tmp_var }->${field_name } = ' )
1063+ g.expr (init_field.expr)
1064+ g.writeln (';' )
1065+ }
1066+ // Handle fields with default values
1067+ for field in val_sym.info.fields {
1068+ mut found := false
1069+ for init_field in val.init_fields {
1070+ if init_field.name == field.name {
1071+ found = true
1072+ break
1073+ }
1074+ }
1075+ if ! found && field.has_default_expr {
1076+ field_name := c_name (field.name)
1077+ g.write ('${tmp_var }->${field_name } = ' )
1078+ g.expr (field.default_expr)
1079+ g.writeln (';' )
1080+ }
1081+ }
1082+ }
1083+ g.empty_line = false
1084+ g.write2 (stmt_str, tmp_var)
10401085 } else {
10411086 old_inside_assign_fn_var := g.inside_assign_fn_var
10421087 g.inside_assign_fn_var = val is ast.PrefixExpr && val.op == .amp
10431088 && is_fn_var
10441089 g.expr (val)
10451090 g.inside_assign_fn_var = old_inside_assign_fn_var
10461091 }
1047- if ! is_fn_var && is_auto_heap && ! is_option_auto_heap {
1092+ if ! is_fn_var && is_auto_heap && ! is_option_auto_heap
1093+ && ! is_large_struct_heap {
10481094 if aligned != 0 {
10491095 g.write ('), ${aligned })' )
10501096 } else {
0 commit comments