diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index c3ceff2b9c4012..3ff7417c5169ea 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -94,9 +94,11 @@ pub mut: pointer_size int // cache for type_to_str_using_aliases cached_type_to_str map[u64]string - anon_struct_names map[string]int // anon struct name -> struct sym idx - // counter for anon struct, avoid name conflicts. + // counters and maps for anon structs and unions, to avoid name conflicts. + anon_struct_names map[string]int // anon struct name -> struct sym idx anon_struct_counter int + anon_union_names map[string]int // anon union name -> union sym idx + anon_union_counter int } // used by vls to avoid leaks @@ -912,6 +914,11 @@ pub fn (mut t Table) register_anon_struct(name string, sym_idx int) { t.anon_struct_names[name] = sym_idx } +@[inline] +pub fn (mut t Table) register_anon_union(name string, sym_idx int) { + t.anon_union_names[name] = sym_idx +} + pub fn (t &Table) known_type(name string) bool { return t.type_idxs[name] != 0 || t.parsing_type == name || name in ['i32', 'byte'] } diff --git a/vlib/v/fmt/tests/union_with_nested_union_keep.vv b/vlib/v/fmt/tests/union_with_nested_union_keep.vv new file mode 100644 index 00000000000000..4618c3c031b63c --- /dev/null +++ b/vlib/v/fmt/tests/union_with_nested_union_keep.vv @@ -0,0 +1,8 @@ +union MyNested1 { + a i32 + b i32 + nested_union union { + c f32 + d char + } +} diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 90b2317a40c546..fd6b367f6d94ea 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -1413,6 +1413,10 @@ fn (mut g Gen) write_results() { ck := c_name(k) g.typedefs.writeln('typedef struct ${ck} ${ck};') } + for k, _ in g.table.anon_union_names { + ck := c_name(k) + g.typedefs.writeln('typedef union ${ck} ${ck};') + } } fn (mut g Gen) find_or_register_shared(t ast.Type, base string) string { diff --git a/vlib/v/parser/struct.v b/vlib/v/parser/struct.v index 1c09398012a31c..3c1d4b8037660c 100644 --- a/vlib/v/parser/struct.v +++ b/vlib/v/parser/struct.v @@ -37,8 +37,13 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl { return ast.StructDecl{} } mut name := if is_anon { - p.table.anon_struct_counter++ - '_VAnonStruct${p.table.anon_struct_counter}' + if is_union { + p.table.anon_union_counter++ + '_VAnonUnion${p.table.anon_union_counter}' + } else { + p.table.anon_struct_counter++ + '_VAnonStruct${p.table.anon_struct_counter}' + } } else { p.check_name() } @@ -241,8 +246,11 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl { // struct field field_name = p.check_name() p.inside_struct_field_decl = true - if p.tok.kind == .key_struct - || (p.tok.kind == .key_shared && p.peek_tok.kind == .key_struct) { + is_anon_struct := p.tok.kind == .key_struct + || (p.tok.kind == .key_shared && p.peek_tok.kind == .key_struct) + is_anon_union := p.tok.kind == .key_union + || (p.tok.kind == .key_shared && p.peek_tok.kind == .key_union) + if is_anon_struct || is_anon_union { // Anon structs field_is_shared := p.tok.kind == .key_shared p.anon_struct_decl = p.struct_decl(true) @@ -402,7 +410,11 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl { } mut ret := p.table.register_sym(sym) if is_anon { - p.table.register_anon_struct(name, ret) + if is_union { + p.table.register_anon_union(name, ret) + } else { + p.table.register_anon_struct(name, ret) + } } // allow duplicate c struct declarations if ret == -1 && language != .c { diff --git a/vlib/v/tests/unions/nested_union_test.v b/vlib/v/tests/unions/nested_union_test.v new file mode 100644 index 00000000000000..bb5092d6c9ce91 --- /dev/null +++ b/vlib/v/tests/unions/nested_union_test.v @@ -0,0 +1,28 @@ +union MyNested1 { +mut: + a i32 + b i32 + nested_union union { + mut: + c f32 + d char + } +} + +fn test_nested_unions() { + mut m := MyNested1{} + unsafe { + m.a = 12 + assert m.b == 12 + println(m.a) + m.b = -99 + assert m.b == -99 + println(m.b) + m.nested_union.c = 3.14 + assert m.nested_union.c == 3.14 + println(m.nested_union.c) + m.nested_union.d = 88 + println(int(m.nested_union.d)) + assert int(m.nested_union.d) == 88 + } +}