aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorSteven Kabbes <[email protected]>2022-05-17 21:23:43 -0700
committerRon Evans <[email protected]>2022-05-19 08:02:32 +0200
commit4c7449efe5f220eaa4ec0b76af83a0bc8ec0eac2 (patch)
tree098a9e16114e278a2822e1d4129a806e01689da8
parent995e815b6392316fdac7526f8f48112984241092 (diff)
downloadtinygo-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.go6
-rw-r--r--testdata/reflect.go10
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.