--- /dev/null
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 11925. Structs with zero-length trailing fields are now
+// padded by the Go compiler.
+
+package cgotest
+
+/*
+struct a11925 {
+ int i;
+ char a[0];
+ char b[0];
+};
+
+struct b11925 {
+ int i;
+ char a[0];
+ char b[];
+};
+*/
+import "C"
+
+import (
+ "testing"
+ "unsafe"
+)
+
+func test11925(t *testing.T) {
+ if C.sizeof_struct_a11925 != unsafe.Sizeof(C.struct_a11925{}) {
+ t.Errorf("size of a changed: C %d, Go %d", C.sizeof_struct_a11925, unsafe.Sizeof(C.struct_a11925{}))
+ }
+ if C.sizeof_struct_b11925 != unsafe.Sizeof(C.struct_b11925{}) {
+ t.Errorf("size of b changed: C %d, Go %d", C.sizeof_struct_b11925, unsafe.Sizeof(C.struct_b11925{}))
+ }
+}
}
// Add padding of given size to fld.
-func (c *typeConv) pad(fld []*ast.Field, size int64) []*ast.Field {
+func (c *typeConv) pad(fld []*ast.Field, sizes []int64, size int64) ([]*ast.Field, []int64) {
n := len(fld)
fld = fld[0 : n+1]
fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident("_")}, Type: c.Opaque(size)}
- return fld
+ sizes = sizes[0 : n+1]
+ sizes[n] = size
+ return fld, sizes
}
// Struct conversion: return Go and (gc) C syntax for type.
var buf bytes.Buffer
buf.WriteString("struct {")
fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field
+ sizes := make([]int64, 0, 2*len(dt.Field)+1)
off := int64(0)
// Rename struct fields that happen to be named Go keywords into
anon := 0
for _, f := range dt.Field {
if f.ByteOffset > off {
- fld = c.pad(fld, f.ByteOffset-off)
+ fld, sizes = c.pad(fld, sizes, f.ByteOffset-off)
off = f.ByteOffset
}
ident[name] = name
}
fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident(ident[name])}, Type: tgo}
+ sizes = sizes[0 : n+1]
+ sizes[n] = size
off += size
buf.WriteString(t.C.String())
buf.WriteString(" ")
}
}
if off < dt.ByteSize {
- fld = c.pad(fld, dt.ByteSize-off)
+ fld, sizes = c.pad(fld, sizes, dt.ByteSize-off)
off = dt.ByteSize
}
+
+ // If the last field in a non-zero-sized struct is zero-sized
+ // the compiler is going to pad it by one (see issue 9401).
+ // We can't permit that, because then the size of the Go
+ // struct will not be the same as the size of the C struct.
+ // Our only option in such a case is to remove the field,
+ // which means that it can not be referenced from Go.
+ for off > 0 && sizes[len(sizes)-1] == 0 {
+ n := len(sizes)
+ fld = fld[0 : n-1]
+ sizes = sizes[0 : n-1]
+ }
+
if off != dt.ByteSize {
fatalf("%s: struct size calculation error off=%d bytesize=%d", lineno(pos), off, dt.ByteSize)
}