diff options
author | Steven Kabbes <[email protected]> | 2022-05-17 21:23:43 -0700 |
---|---|---|
committer | Ron Evans <[email protected]> | 2022-05-19 08:02:32 +0200 |
commit | 4c7449efe5f220eaa4ec0b76af83a0bc8ec0eac2 (patch) | |
tree | 098a9e16114e278a2822e1d4129a806e01689da8 | |
parent | 995e815b6392316fdac7526f8f48112984241092 (diff) | |
download | tinygo-4c7449efe5f220eaa4ec0b76af83a0bc8ec0eac2.tar.gz tinygo-4c7449efe5f220eaa4ec0b76af83a0bc8ec0eac2.zip |
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).
-rw-r--r-- | compiler/sizes.go | 6 | ||||
-rw-r--r-- | testdata/reflect.go | 10 |
2 files changed, 16 insertions, 0 deletions
diff --git a/compiler/sizes.go b/compiler/sizes.go index b46d34363..57108323b 100644 --- a/compiler/sizes.go +++ b/compiler/sizes.go @@ -21,6 +21,12 @@ func (s *stdSizes) Alignof(T types.Type) int64 { // of alignment of the elements and fields, respectively. switch t := T.Underlying().(type) { case *types.Array: + if t.Len() == 0 { + // 0-sized arrays, always have 0 size. + // And from the spec, should have an alignment of _at least_ 1 + return 1 + } + // spec: "For a variable x of array type: unsafe.Alignof(x) // is the same as unsafe.Alignof(x[0]), but at least 1." return s.Alignof(t.Elem()) diff --git a/testdata/reflect.go b/testdata/reflect.go index 7cc5fa7bb..f48683150 100644 --- a/testdata/reflect.go +++ b/testdata/reflect.go @@ -52,6 +52,12 @@ func main() { println("\nvalues of interfaces") var zeroSlice []byte var zeroFunc func() + // by embedding a 0-array func type in your struct, it is not comparable + type doNotCompare [0]func() + type notComparable struct { + doNotCompare + data *int32 + } var zeroMap map[string]int var zeroChan chan int n := 42 @@ -170,6 +176,10 @@ func main() { assertSize(reflect.TypeOf(new(int)).Size() == unsafe.Sizeof(new(int)), "*int") assertSize(reflect.TypeOf(zeroFunc).Size() == unsafe.Sizeof(zeroFunc), "func()") + // make sure embedding a zero-sized "not comparable" struct does not add size to a struct + assertSize(reflect.TypeOf(doNotCompare{}).Size() == unsafe.Sizeof(doNotCompare{}), "[0]func()") + assertSize(unsafe.Sizeof(notComparable{}) == unsafe.Sizeof((*int32)(nil)), "struct{[0]func(); *int32}") + // Test that offset is correctly calculated. // This doesn't just test reflect but also (indirectly) that unsafe.Alignof // works correctly. |