Skip to content

Commit 4c7449e

Browse files
skabbesdeadprogram
authored andcommitted
compiler: alignof [0]func() = 1
In the go protobuf code, a pattern is used to statically prevent comparable structs by embedding: ``` type DoNotCompare [0]func() type message struct { DoNotCompare data *uint32 } ``` Previously, sizezof(message{}) is 2 words large, but it only needs to be 1 byte. Making it be 1 byte allows protobufs to compile slightly more (though not all the way).
1 parent 995e815 commit 4c7449e

File tree

2 files changed

+16
-0
lines changed

2 files changed

+16
-0
lines changed

compiler/sizes.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ func (s *stdSizes) Alignof(T types.Type) int64 {
2121
// of alignment of the elements and fields, respectively.
2222
switch t := T.Underlying().(type) {
2323
case *types.Array:
24+
if t.Len() == 0 {
25+
// 0-sized arrays, always have 0 size.
26+
// And from the spec, should have an alignment of _at least_ 1
27+
return 1
28+
}
29+
2430
// spec: "For a variable x of array type: unsafe.Alignof(x)
2531
// is the same as unsafe.Alignof(x[0]), but at least 1."
2632
return s.Alignof(t.Elem())

testdata/reflect.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ func main() {
5252
println("\nvalues of interfaces")
5353
var zeroSlice []byte
5454
var zeroFunc func()
55+
// by embedding a 0-array func type in your struct, it is not comparable
56+
type doNotCompare [0]func()
57+
type notComparable struct {
58+
doNotCompare
59+
data *int32
60+
}
5561
var zeroMap map[string]int
5662
var zeroChan chan int
5763
n := 42
@@ -170,6 +176,10 @@ func main() {
170176
assertSize(reflect.TypeOf(new(int)).Size() == unsafe.Sizeof(new(int)), "*int")
171177
assertSize(reflect.TypeOf(zeroFunc).Size() == unsafe.Sizeof(zeroFunc), "func()")
172178

179+
// make sure embedding a zero-sized "not comparable" struct does not add size to a struct
180+
assertSize(reflect.TypeOf(doNotCompare{}).Size() == unsafe.Sizeof(doNotCompare{}), "[0]func()")
181+
assertSize(unsafe.Sizeof(notComparable{}) == unsafe.Sizeof((*int32)(nil)), "struct{[0]func(); *int32}")
182+
173183
// Test that offset is correctly calculated.
174184
// This doesn't just test reflect but also (indirectly) that unsafe.Alignof
175185
// works correctly.

0 commit comments

Comments
 (0)