From a03115eff7ee03f978e351e50ebc9dc7ba66b233 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sun, 3 Apr 2022 15:45:45 +0800 Subject: [PATCH] union: support embedded field --- cl/codebuild.go | 37 ++++++++++++++++++++++++++++++------- cl/type_and_var.go | 1 + testdata/union/union.c | 19 ++++++++++++++++++- 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/cl/codebuild.go b/cl/codebuild.go index b5c5545..e5b7bf9 100644 --- a/cl/codebuild.go +++ b/cl/codebuild.go @@ -42,18 +42,42 @@ func newUnionBuilder() *unionBuilder { return &unionBuilder{} } +func unionEmbeddedField(ctx *blockCtx, fields []*gox.UnionField, t *types.Named, off int) []*gox.UnionField { + o := t.Underlying().(*types.Struct) + for i, n := 0, o.NumFields(); i < n; i++ { + fld := o.Field(i) + fldType := fld.Type() + if fld.Embedded() { + fields = unionEmbeddedField(ctx, fields, fldType.(*types.Named), off) + } else { + fields = append(fields, &gox.UnionField{ + Name: fld.Name(), + Off: off, + Type: fldType, + }) + } + off += ctx.sizeof(fldType) + } + return fields +} + func (p *unionBuilder) Type(ctx *blockCtx, t *types.Named) *types.Struct { var fldLargest *gox.UnionField - var lenLargest int - for _, fld := range p.fields { + var fields = p.fields + var lenLargest, n = 0, len(fields) + for i := 0; i < n; i++ { + fld := fields[i] if len := ctx.sizeof(fld.Type); len > lenLargest { fldLargest, lenLargest = fld, len } + if fld.Name == "" { // embedded + fields = unionEmbeddedField(ctx, fields, fld.Type.(*types.Named), 0) + } } flds := make([]*types.Var, 0, 1) if fldLargest != nil { pkg := ctx.pkg - pkg.SetVFields(t, gox.NewUnionFields(p.fields)) + pkg.SetVFields(t, gox.NewUnionFields(fields)) fld := types.NewField(fldLargest.Pos, pkg.Types, fldLargest.Name, fldLargest.Type, false) flds = append(flds, fld) } @@ -61,16 +85,15 @@ func (p *unionBuilder) Type(ctx *blockCtx, t *types.Named) *types.Struct { } func (p *unionBuilder) Field(ctx *blockCtx, pos token.Pos, typ types.Type, name string, embedded bool) { + if embedded { + name = "" + } fld := &gox.UnionField{ Name: name, - Off: 0, // TODO Type: typ, Pos: pos, } p.fields = append(p.fields, fld) - if name == "" { - log.Fatalln("unionBuilder.Field TODO: embedded") - } } // ----------------------------------------------------------------------------- diff --git a/cl/type_and_var.go b/cl/type_and_var.go index 29b4ebb..0605216 100644 --- a/cl/type_and_var.go +++ b/cl/type_and_var.go @@ -114,6 +114,7 @@ func toUnionType(ctx *blockCtx, t *types.Named, unio *ast.Node, ns string) types } break } + case ast.IndirectFieldDecl: default: log.Fatalln("toUnionType: unknown field kind =", decl.Kind) } diff --git a/testdata/union/union.c b/testdata/union/union.c index b558354..332d172 100644 --- a/testdata/union/union.c +++ b/testdata/union/union.c @@ -1,11 +1,17 @@ #include typedef union { - long a; + int a; unsigned short b; struct bar { unsigned short low, high; } c; + struct { + unsigned short low; + struct { + unsigned short high; + }; + }; } foo; int main() { @@ -16,5 +22,16 @@ int main() { printf( "foo.a = %d, foo.b = %d, foo.c.low = %d, foo.c.high = %d\n", foo.a, foo.b, foo.c.low, foo.c.high); + printf( + "foo.low = %d, foo.high = %d\n", + foo.low, foo.high); + foo.low = 5; + foo.high = 6; + printf( + "foo.a = %d, foo.b = %d, foo.c.low = %d, foo.c.high = %d\n", + foo.a, foo.b, foo.c.low, foo.c.high); + printf( + "foo.low = %d, foo.high = %d\n", + foo.low, foo.high); return 0; }