diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index d09e7a02bd02b3..7888e4753b81bc 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -1473,12 +1473,20 @@ pub fn (mut g Gen) write_typedef_types() { def_str = def_str.replace_once('(*)', '(*${styp}[${len}])') g.type_definitions.writeln(def_str) } else if !info.is_fn_ret { - g.type_definitions.writeln('typedef ${fixed} ${styp} [${len}];') base := g.typ(info.elem_type.clear_option_and_result()) if info.elem_type.has_flag(.option) && base !in g.options_forward { - g.options_forward << base - } else if info.elem_type.has_flag(.result) && base !in g.results_forward { - g.results_forward << base + lock g.done_options { + if base !in g.done_options { + g.type_definitions.writeln('typedef ${fixed} ${styp} [${len}];') + g.options_forward << base + g.done_options << styp + } + } + } else { + g.type_definitions.writeln('typedef ${fixed} ${styp} [${len}];') + if info.elem_type.has_flag(.result) && base !in g.results_forward { + g.results_forward << base + } } } } @@ -6396,6 +6404,27 @@ fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) { match sym.info { ast.Struct { if !struct_names[name] { + // generate field option types for fixed array of option struct before struct declaration + opt_fields := sym.info.fields.filter(g.table.final_sym(it.typ).kind == .array_fixed) + for opt_field in opt_fields { + field_sym := g.table.final_sym(opt_field.typ) + arr := field_sym.info as ast.ArrayFixed + if !arr.elem_type.has_flag(.option) { + continue + } + styp := field_sym.cname + mut fixed_elem_name := g.typ(arr.elem_type.set_nr_muls(0)) + if arr.elem_type.is_ptr() { + fixed_elem_name += '*'.repeat(arr.elem_type.nr_muls()) + } + len := arr.size + lock g.done_options { + if styp !in g.done_options { + g.type_definitions.writeln('typedef ${fixed_elem_name} ${styp} [${len}];') + g.done_options << styp + } + } + } g.struct_decl(sym.info, name, false) struct_names[name] = true } @@ -6479,7 +6508,20 @@ fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) { g.type_definitions.writeln(def_str) } else if elem_sym.info !is ast.ArrayFixed || (elem_sym.info as ast.ArrayFixed).size > 0 { - g.type_definitions.writeln('typedef ${fixed_elem_name} ${styp} [${len}];') + // fixed array of option struct must be defined backwards + if sym.info.elem_type.has_flag(.option) && elem_sym.info is ast.Struct { + styp_elem, base := g.option_type_name(sym.info.elem_type) + lock g.done_options { + if base !in g.done_options { + g.done_options << base + g.typedefs.writeln('typedef struct ${styp_elem} ${styp_elem};') + g.type_definitions.writeln('${g.option_type_text(styp_elem, + base)};') + } + } + } else { + g.type_definitions.writeln('typedef ${fixed_elem_name} ${styp} [${len}];') + } } } } diff --git a/vlib/v/tests/option_array_fixed_struct_test.v b/vlib/v/tests/option_array_fixed_struct_test.v new file mode 100644 index 00000000000000..8896daea672477 --- /dev/null +++ b/vlib/v/tests/option_array_fixed_struct_test.v @@ -0,0 +1,16 @@ +struct Test {} + +struct Test2 { + a [10]?Test +} + +struct Test3 { + a [10]?Test +} + +fn test_main() { + a := Test2{} + b := Test3{} + assert dump(Test2{}) == a + assert dump(Test3{}) == b +}