aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/reflect
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2017-01-14 00:05:42 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2017-01-14 00:05:42 +0000
commitc2047754c300b68c05d65faa8dc2925fe67b71b4 (patch)
treee183ae81a1f48a02945cb6de463a70c5be1b06f6 /libgo/go/reflect
parent829afb8f05602bb31c9c597b24df7377fed4f059 (diff)
downloadgcc-c2047754c300b68c05d65faa8dc2925fe67b71b4.zip
gcc-c2047754c300b68c05d65faa8dc2925fe67b71b4.tar.gz
gcc-c2047754c300b68c05d65faa8dc2925fe67b71b4.tar.bz2
libgo: update to Go 1.8 release candidate 1
Compiler changes: * Change map assignment to use mapassign and assign value directly. * Change string iteration to use decoderune, faster for ASCII strings. * Change makeslice to take int, and use makeslice64 for larger values. * Add new noverflow field to hmap struct used for maps. Unresolved problems, to be fixed later: * Commented out test in go/types/sizes_test.go that doesn't compile. * Commented out reflect.TestStructOf test for padding after zero-sized field. Reviewed-on: https://go-review.googlesource.com/35231 gotools/: Updates for Go 1.8rc1. * Makefile.am (go_cmd_go_files): Add bug.go. (s-zdefaultcc): Write defaultPkgConfig. * Makefile.in: Rebuild. From-SVN: r244456
Diffstat (limited to 'libgo/go/reflect')
-rw-r--r--libgo/go/reflect/all_test.go247
-rw-r--r--libgo/go/reflect/deepequal.go11
-rw-r--r--libgo/go/reflect/example_test.go41
-rw-r--r--libgo/go/reflect/export_test.go4
-rw-r--r--libgo/go/reflect/makefunc.go2
-rw-r--r--libgo/go/reflect/swapper.go74
-rw-r--r--libgo/go/reflect/type.go122
-rw-r--r--libgo/go/reflect/value.go4
8 files changed, 444 insertions, 61 deletions
diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go
index e601c2c..f51e95f 100644
--- a/libgo/go/reflect/all_test.go
+++ b/libgo/go/reflect/all_test.go
@@ -648,6 +648,20 @@ var (
type self struct{}
+type Loop *Loop
+type Loopy interface{}
+
+var loop1, loop2 Loop
+var loopy1, loopy2 Loopy
+
+func init() {
+ loop1 = &loop2
+ loop2 = &loop1
+
+ loopy1 = &loopy2
+ loopy2 = &loopy1
+}
+
var deepEqualTests = []DeepEqualTest{
// Equalities
{nil, nil, true},
@@ -706,6 +720,12 @@ var deepEqualTests = []DeepEqualTest{
{&[3]interface{}{1, 2, 4}, &[3]interface{}{1, 2, "s"}, false},
{Basic{1, 0.5}, NotBasic{1, 0.5}, false},
{map[uint]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, false},
+
+ // Possible loops.
+ {&loop1, &loop1, true},
+ {&loop1, &loop2, true},
+ {&loopy1, &loopy1, true},
+ {&loopy1, &loopy2, true},
}
func TestDeepEqual(t *testing.T) {
@@ -1535,6 +1555,34 @@ func BenchmarkCall(b *testing.B) {
})
}
+func BenchmarkCallArgCopy(b *testing.B) {
+ byteArray := func(n int) Value {
+ return Zero(ArrayOf(n, TypeOf(byte(0))))
+ }
+ sizes := [...]struct {
+ fv Value
+ arg Value
+ }{
+ {ValueOf(func(a [128]byte) {}), byteArray(128)},
+ {ValueOf(func(a [256]byte) {}), byteArray(256)},
+ {ValueOf(func(a [1024]byte) {}), byteArray(1024)},
+ {ValueOf(func(a [4096]byte) {}), byteArray(4096)},
+ {ValueOf(func(a [65536]byte) {}), byteArray(65536)},
+ }
+ for _, size := range sizes {
+ bench := func(b *testing.B) {
+ args := []Value{size.arg}
+ b.SetBytes(int64(size.arg.Len()))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ size.fv.Call(args)
+ }
+ }
+ name := fmt.Sprintf("size=%v", size.arg.Len())
+ b.Run(name, bench)
+ }
+}
+
func TestMakeFunc(t *testing.T) {
f := dummy
fv := MakeFunc(TypeOf(f), func(in []Value) []Value { return in })
@@ -2277,25 +2325,39 @@ func TestFieldPkgPath(t *testing.T) {
unexported string
OtherPkgFields
}{})
- for _, test := range []struct {
+
+ type pkgpathTest struct {
index []int
pkgPath string
anonymous bool
- }{
+ }
+
+ checkPkgPath := func(name string, s []pkgpathTest) {
+ for _, test := range s {
+ f := typ.FieldByIndex(test.index)
+ if got, want := f.PkgPath, test.pkgPath; got != want {
+ t.Errorf("%s: Field(%d).PkgPath = %q, want %q", name, test.index, got, want)
+ }
+ if got, want := f.Anonymous, test.anonymous; got != want {
+ t.Errorf("%s: Field(%d).Anonymous = %v, want %v", name, test.index, got, want)
+ }
+ }
+ }
+
+ checkPkgPath("testStruct", []pkgpathTest{
{[]int{0}, "", false}, // Exported
{[]int{1}, "reflect_test", false}, // unexported
{[]int{2}, "", true}, // OtherPkgFields
{[]int{2, 0}, "", false}, // OtherExported
{[]int{2, 1}, "reflect", false}, // otherUnexported
- } {
- f := typ.FieldByIndex(test.index)
- if got, want := f.PkgPath, test.pkgPath; got != want {
- t.Errorf("Field(%d).PkgPath = %q, want %q", test.index, got, want)
- }
- if got, want := f.Anonymous, test.anonymous; got != want {
- t.Errorf("Field(%d).Anonymous = %v, want %v", test.index, got, want)
- }
- }
+ })
+
+ type localOtherPkgFields OtherPkgFields
+ typ = TypeOf(localOtherPkgFields{})
+ checkPkgPath("localOtherPkgFields", []pkgpathTest{
+ {[]int{0}, "", false}, // OtherExported
+ {[]int{1}, "reflect", false}, // otherUnexported
+ })
}
func TestVariadicType(t *testing.T) {
@@ -3077,6 +3139,9 @@ func ReadWriterV(x io.ReadWriter) Value {
}
type Empty struct{}
+type MyStruct struct {
+ x int `some:"tag"`
+}
type MyString string
type MyBytes []byte
type MyRunes []int32
@@ -3388,6 +3453,35 @@ var convertTests = []struct {
{V((func())(nil)), V(MyFunc(nil))},
{V((MyFunc)(nil)), V((func())(nil))},
+ // structs with different tags
+ {V(struct {
+ x int `some:"foo"`
+ }{}), V(struct {
+ x int `some:"bar"`
+ }{})},
+
+ {V(struct {
+ x int `some:"bar"`
+ }{}), V(struct {
+ x int `some:"foo"`
+ }{})},
+
+ {V(MyStruct{}), V(struct {
+ x int `some:"foo"`
+ }{})},
+
+ {V(struct {
+ x int `some:"foo"`
+ }{}), V(MyStruct{})},
+
+ {V(MyStruct{}), V(struct {
+ x int `some:"bar"`
+ }{})},
+
+ {V(struct {
+ x int `some:"bar"`
+ }{}), V(MyStruct{})},
+
// can convert *byte and *MyByte
{V((*byte)(nil)), V((*MyByte)(nil))},
{V((*MyByte)(nil)), V((*byte)(nil))},
@@ -3973,6 +4067,39 @@ func TestStructOf(t *testing.T) {
}
}
+ // Check size and alignment with a trailing zero-sized field.
+ st = StructOf([]StructField{
+ {
+ Name: "F1",
+ Type: TypeOf(byte(0)),
+ },
+ {
+ Name: "F2",
+ Type: TypeOf([0]*byte{}),
+ },
+ })
+ stt = TypeOf(struct {
+ G1 byte
+ G2 [0]*byte
+ }{})
+ // Broken with gccgo for now--gccgo does not pad structs yet.
+ // if st.Size() != stt.Size() {
+ // t.Errorf("constructed zero-padded struct size = %v, want %v", st.Size(), stt.Size())
+ // }
+ if st.Align() != stt.Align() {
+ t.Errorf("constructed zero-padded struct align = %v, want %v", st.Align(), stt.Align())
+ }
+ if st.FieldAlign() != stt.FieldAlign() {
+ t.Errorf("constructed zero-padded struct field align = %v, want %v", st.FieldAlign(), stt.FieldAlign())
+ }
+ for i := 0; i < st.NumField(); i++ {
+ o1 := st.Field(i).Offset
+ o2 := stt.Field(i).Offset
+ if o1 != o2 {
+ t.Errorf("constructed zero-padded struct field %v offset = %v, want %v", i, o1, o2)
+ }
+ }
+
// check duplicate names
shouldPanic(func() {
StructOf([]StructField{
@@ -5788,3 +5915,101 @@ func BenchmarkNew(b *testing.B) {
New(v)
}
}
+
+func TestSwapper(t *testing.T) {
+ type I int
+ var a, b, c I
+ type pair struct {
+ x, y int
+ }
+ type pairPtr struct {
+ x, y int
+ p *I
+ }
+ type S string
+
+ tests := []struct {
+ in interface{}
+ i, j int
+ want interface{}
+ }{
+ {
+ in: []int{1, 20, 300},
+ i: 0,
+ j: 2,
+ want: []int{300, 20, 1},
+ },
+ {
+ in: []uintptr{1, 20, 300},
+ i: 0,
+ j: 2,
+ want: []uintptr{300, 20, 1},
+ },
+ {
+ in: []int16{1, 20, 300},
+ i: 0,
+ j: 2,
+ want: []int16{300, 20, 1},
+ },
+ {
+ in: []int8{1, 20, 100},
+ i: 0,
+ j: 2,
+ want: []int8{100, 20, 1},
+ },
+ {
+ in: []*I{&a, &b, &c},
+ i: 0,
+ j: 2,
+ want: []*I{&c, &b, &a},
+ },
+ {
+ in: []string{"eric", "sergey", "larry"},
+ i: 0,
+ j: 2,
+ want: []string{"larry", "sergey", "eric"},
+ },
+ {
+ in: []S{"eric", "sergey", "larry"},
+ i: 0,
+ j: 2,
+ want: []S{"larry", "sergey", "eric"},
+ },
+ {
+ in: []pair{{1, 2}, {3, 4}, {5, 6}},
+ i: 0,
+ j: 2,
+ want: []pair{{5, 6}, {3, 4}, {1, 2}},
+ },
+ {
+ in: []pairPtr{{1, 2, &a}, {3, 4, &b}, {5, 6, &c}},
+ i: 0,
+ j: 2,
+ want: []pairPtr{{5, 6, &c}, {3, 4, &b}, {1, 2, &a}},
+ },
+ }
+ for i, tt := range tests {
+ inStr := fmt.Sprint(tt.in)
+ Swapper(tt.in)(tt.i, tt.j)
+ if !DeepEqual(tt.in, tt.want) {
+ t.Errorf("%d. swapping %v and %v of %v = %v; want %v", i, tt.i, tt.j, inStr, tt.in, tt.want)
+ }
+ }
+}
+
+// TestUnaddressableField tests that the reflect package will not allow
+// a type from another package to be used as a named type with an
+// unexported field.
+//
+// This ensures that unexported fields cannot be modified by other packages.
+func TestUnaddressableField(t *testing.T) {
+ var b Buffer // type defined in reflect, a different package
+ var localBuffer struct {
+ buf []byte
+ }
+ lv := ValueOf(&localBuffer).Elem()
+ rv := ValueOf(b)
+ shouldPanic(func() {
+ lv.Set(rv)
+ })
+}
diff --git a/libgo/go/reflect/deepequal.go b/libgo/go/reflect/deepequal.go
index 9770358..f3fd704 100644
--- a/libgo/go/reflect/deepequal.go
+++ b/libgo/go/reflect/deepequal.go
@@ -30,9 +30,13 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool {
}
// if depth > 10 { panic("deepValueEqual") } // for debugging
+
+ // We want to avoid putting more in the visited map than we need to.
+ // For any possible reference cycle that might be encountered,
+ // hard(t) needs to return true for at least one of the types in the cycle.
hard := func(k Kind) bool {
switch k {
- case Array, Map, Slice, Struct:
+ case Map, Slice, Ptr, Interface:
return true
}
return false
@@ -142,8 +146,9 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool {
//
// Interface values are deeply equal if they hold deeply equal concrete values.
//
-// Map values are deeply equal if they are the same map object
-// or if they have the same length and their corresponding keys
+// Map values are deeply equal when all of the following are true:
+// they are both nil or both non-nil, they have the same length,
+// and either they are the same map object or their corresponding keys
// (matched using Go equality) map to deeply equal values.
//
// Pointer values are deeply equal if they are equal using Go's == operator
diff --git a/libgo/go/reflect/example_test.go b/libgo/go/reflect/example_test.go
index 9e2b9b3..f959b95 100644
--- a/libgo/go/reflect/example_test.go
+++ b/libgo/go/reflect/example_test.go
@@ -5,6 +5,8 @@
package reflect_test
import (
+ "bytes"
+ "encoding/json"
"fmt"
"io"
"os"
@@ -107,3 +109,42 @@ func ExampleTypeOf() {
// Output:
// true
}
+
+func ExampleStructOf() {
+ typ := reflect.StructOf([]reflect.StructField{
+ {
+ Name: "Height",
+ Type: reflect.TypeOf(float64(0)),
+ Tag: `json:"height"`,
+ },
+ {
+ Name: "Age",
+ Type: reflect.TypeOf(int(0)),
+ Tag: `json:"age"`,
+ },
+ })
+
+ v := reflect.New(typ).Elem()
+ v.Field(0).SetFloat(0.4)
+ v.Field(1).SetInt(2)
+ s := v.Addr().Interface()
+
+ w := new(bytes.Buffer)
+ if err := json.NewEncoder(w).Encode(s); err != nil {
+ panic(err)
+ }
+
+ fmt.Printf("value: %+v\n", s)
+ fmt.Printf("json: %s", w.Bytes())
+
+ r := bytes.NewReader([]byte(`{"height":1.5,"age":10}`))
+ if err := json.NewDecoder(r).Decode(s); err != nil {
+ panic(err)
+ }
+ fmt.Printf("value: %+v\n", s)
+
+ // Output:
+ // value: &{Height:0.4 Age:2}
+ // json: {"height":0.4,"age":2}
+ // value: &{Height:1.5 Age:10}
+}
diff --git a/libgo/go/reflect/export_test.go b/libgo/go/reflect/export_test.go
index a06e8d0..92b1302 100644
--- a/libgo/go/reflect/export_test.go
+++ b/libgo/go/reflect/export_test.go
@@ -83,3 +83,7 @@ func ResolveReflectName(s string) {
resolveReflectName(newName(s, "", "", false))
}
*/
+
+type Buffer struct {
+ buf []byte
+}
diff --git a/libgo/go/reflect/makefunc.go b/libgo/go/reflect/makefunc.go
index 3a9fd28..91df328 100644
--- a/libgo/go/reflect/makefunc.go
+++ b/libgo/go/reflect/makefunc.go
@@ -12,8 +12,8 @@ import (
// makeFuncImpl is the closure value implementing the function
// returned by MakeFunc.
+// The first three words are layed out like ffi_go_closure.
type makeFuncImpl struct {
- // These first three words are layed out like ffi_go_closure.
code uintptr
ffi_cif unsafe.Pointer
ffi_fun func(unsafe.Pointer, unsafe.Pointer)
diff --git a/libgo/go/reflect/swapper.go b/libgo/go/reflect/swapper.go
new file mode 100644
index 0000000..5441cb0
--- /dev/null
+++ b/libgo/go/reflect/swapper.go
@@ -0,0 +1,74 @@
+// Copyright 2016 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.
+
+package reflect
+
+import "unsafe"
+
+// Swapper returns a function that swaps the elements in the provided
+// slice.
+//
+// Swapper panics if the provided interface is not a slice.
+func Swapper(slice interface{}) func(i, j int) {
+ v := ValueOf(slice)
+ if v.Kind() != Slice {
+ panic(&ValueError{Method: "Swapper", Kind: v.Kind()})
+ }
+ // Fast path for slices of size 0 and 1. Nothing to swap.
+ switch v.Len() {
+ case 0:
+ return func(i, j int) { panic("reflect: slice index out of range") }
+ case 1:
+ return func(i, j int) {
+ if i != 0 || j != 0 {
+ panic("reflect: slice index out of range")
+ }
+ }
+ }
+
+ typ := v.Type().Elem().(*rtype)
+ size := typ.Size()
+ hasPtr := typ.kind&kindNoPointers == 0
+
+ // Some common & small cases, without using memmove:
+ if hasPtr {
+ if size == ptrSize {
+ ps := *(*[]unsafe.Pointer)(v.ptr)
+ return func(i, j int) { ps[i], ps[j] = ps[j], ps[i] }
+ }
+ if typ.Kind() == String {
+ ss := *(*[]string)(v.ptr)
+ return func(i, j int) { ss[i], ss[j] = ss[j], ss[i] }
+ }
+ } else {
+ switch size {
+ case 8:
+ is := *(*[]int64)(v.ptr)
+ return func(i, j int) { is[i], is[j] = is[j], is[i] }
+ case 4:
+ is := *(*[]int32)(v.ptr)
+ return func(i, j int) { is[i], is[j] = is[j], is[i] }
+ case 2:
+ is := *(*[]int16)(v.ptr)
+ return func(i, j int) { is[i], is[j] = is[j], is[i] }
+ case 1:
+ is := *(*[]int8)(v.ptr)
+ return func(i, j int) { is[i], is[j] = is[j], is[i] }
+ }
+ }
+
+ s := (*sliceHeader)(v.ptr)
+ tmp := unsafe_New(typ) // swap scratch space
+
+ return func(i, j int) {
+ if uint(i) >= uint(s.Len) || uint(j) >= uint(s.Len) {
+ panic("reflect: slice index out of range")
+ }
+ val1 := arrayAt(s.Data, i, size)
+ val2 := arrayAt(s.Data, j, size)
+ typedmemmove(typ, tmp, val1)
+ typedmemmove(typ, val1, val2)
+ typedmemmove(typ, val2, tmp)
+ }
+}
diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go
index 4f13f14..07a355d 100644
--- a/libgo/go/reflect/type.go
+++ b/libgo/go/reflect/type.go
@@ -28,6 +28,9 @@ import (
// Use the Kind method to find out the kind of type before
// calling kind-specific methods. Calling a method
// inappropriate to the kind of type causes a run-time panic.
+//
+// Type values are comparable, such as with the == operator.
+// Two Type values are equal if they represent identical types.
type Type interface {
// Methods applicable to all types.
@@ -59,7 +62,7 @@ type Type interface {
// method signature, without a receiver, and the Func field is nil.
MethodByName(string) (Method, bool)
- // NumMethod returns the number of methods in the type's method set.
+ // NumMethod returns the number of exported methods in the type's method set.
NumMethod() int
// Name returns the type's name within its package.
@@ -79,7 +82,7 @@ type Type interface {
// String returns a string representation of the type.
// The string representation may use shortened package names
// (e.g., base64 instead of "encoding/base64") and is not
- // guaranteed to be unique among types. To test for equality,
+ // guaranteed to be unique among types. To test for type identity,
// compare the Types directly.
String() string
@@ -155,9 +158,18 @@ type Type interface {
// and a boolean indicating if the field was found.
FieldByName(name string) (StructField, bool)
- // FieldByNameFunc returns the first struct field with a name
+ // FieldByNameFunc returns the struct field with a name
// that satisfies the match function and a boolean indicating if
// the field was found.
+ //
+ // FieldByNameFunc considers the fields in the struct itself
+ // and then the fields in any anonymous structs, in breadth first order,
+ // stopping at the shallowest nesting depth containing one or more
+ // fields satisfying the match function. If multiple fields at that depth
+ // satisfy the match function, they cancel each other
+ // and FieldByNameFunc returns no match.
+ // This behavior mirrors Go's handling of name lookup in
+ // structs containing anonymous fields.
FieldByNameFunc(match func(string) bool) (StructField, bool)
// In returns the type of a function type's i'th input parameter.
@@ -826,7 +838,7 @@ func (tag StructTag) Get(key string) string {
// the value returned by Lookup is unspecified.
func (tag StructTag) Lookup(key string) (value string, ok bool) {
// When modifying this code, also update the validateStructTag code
- // in golang.org/x/tools/cmd/vet/structtag.go.
+ // in cmd/vet/structtag.go.
for tag != "" {
// Skip leading space.
@@ -1157,12 +1169,11 @@ func (t *rtype) ptrTo() *rtype {
// Create a new ptrType starting with the description
// of an *unsafe.Pointer.
- p = new(ptrType)
var iptr interface{} = (*unsafe.Pointer)(nil)
prototype := *(**ptrType)(unsafe.Pointer(&iptr))
- *p = *prototype
+ pp := *prototype
- p.string = &s
+ pp.string = &s
// For the type structures linked into the binary, the
// compiler provides a good hash of the string.
@@ -1171,17 +1182,17 @@ func (t *rtype) ptrTo() *rtype {
// old hash and the new "*".
// p.hash = fnv1(t.hash, '*')
// This is the gccgo version.
- p.hash = (t.hash << 4) + 9
+ pp.hash = (t.hash << 4) + 9
- p.uncommonType = nil
- p.ptrToThis = nil
- p.elem = t
+ pp.uncommonType = nil
+ pp.ptrToThis = nil
+ pp.elem = t
if t.kind&kindNoPointers != 0 {
- p.gc = unsafe.Pointer(&ptrDataGCProg)
+ pp.gc = unsafe.Pointer(&ptrDataGCProg)
} else {
- p.gc = unsafe.Pointer(&ptrGC{
- width: p.size,
+ pp.gc = unsafe.Pointer(&ptrGC{
+ width: pp.size,
op: _GC_PTR,
off: 0,
elemgc: t.gc,
@@ -1189,7 +1200,7 @@ func (t *rtype) ptrTo() *rtype {
})
}
- q := canonicalize(&p.rtype)
+ q := canonicalize(&pp.rtype)
p = (*ptrType)(unsafe.Pointer(q.(*rtype)))
ptrMap.m[t] = p
@@ -1331,10 +1342,22 @@ func directlyAssignable(T, V *rtype) bool {
}
// x's type T and V must have identical underlying types.
- return haveIdenticalUnderlyingType(T, V)
+ return haveIdenticalUnderlyingType(T, V, true)
+}
+
+func haveIdenticalType(T, V Type, cmpTags bool) bool {
+ if cmpTags {
+ return T == V
+ }
+
+ if T.Name() != V.Name() || T.Kind() != V.Kind() {
+ return false
+ }
+
+ return haveIdenticalUnderlyingType(T.common(), V.common(), false)
}
-func haveIdenticalUnderlyingType(T, V *rtype) bool {
+func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool {
if T == V {
return true
}
@@ -1353,18 +1376,18 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool {
// Composite types.
switch kind {
case Array:
- return T.Elem() == V.Elem() && T.Len() == V.Len()
+ return T.Len() == V.Len() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
case Chan:
// Special case:
// x is a bidirectional channel value, T is a channel type,
// and x's type V and T have identical element types.
- if V.ChanDir() == BothDir && T.Elem() == V.Elem() {
+ if V.ChanDir() == BothDir && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) {
return true
}
// Otherwise continue test for identical underlying type.
- return V.ChanDir() == T.ChanDir() && T.Elem() == V.Elem()
+ return V.ChanDir() == T.ChanDir() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
case Func:
t := (*funcType)(unsafe.Pointer(T))
@@ -1373,12 +1396,12 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool {
return false
}
for i, typ := range t.in {
- if typ != v.in[i] {
+ if !haveIdenticalType(typ, v.in[i], cmpTags) {
return false
}
}
for i, typ := range t.out {
- if typ != v.out[i] {
+ if !haveIdenticalType(typ, v.out[i], cmpTags) {
return false
}
}
@@ -1395,10 +1418,10 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool {
return false
case Map:
- return T.Key() == V.Key() && T.Elem() == V.Elem()
+ return haveIdenticalType(T.Key(), V.Key(), cmpTags) && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
case Ptr, Slice:
- return T.Elem() == V.Elem()
+ return haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
case Struct:
t := (*structType)(unsafe.Pointer(T))
@@ -1415,10 +1438,10 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool {
if tf.pkgPath != vf.pkgPath && (tf.pkgPath == nil || vf.pkgPath == nil || *tf.pkgPath != *vf.pkgPath) {
return false
}
- if tf.typ != vf.typ {
+ if !haveIdenticalType(tf.typ, vf.typ, cmpTags) {
return false
}
- if tf.tag != vf.tag && (tf.tag == nil || vf.tag == nil || *tf.tag != *vf.tag) {
+ if cmpTags && tf.tag != vf.tag && (tf.tag == nil || vf.tag == nil || *tf.tag != *vf.tag) {
return false
}
if tf.offset != vf.offset {
@@ -1539,8 +1562,7 @@ func ChanOf(dir ChanDir, t Type) Type {
// Make a channel type.
var ichan interface{} = (chan unsafe.Pointer)(nil)
prototype := *(**chanType)(unsafe.Pointer(&ichan))
- ch := new(chanType)
- *ch = *prototype
+ ch := *prototype
ch.dir = uintptr(dir)
ch.string = &s
@@ -1602,8 +1624,7 @@ func MapOf(key, elem Type) Type {
// Make a map type.
var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil)
- mt := new(mapType)
- *mt = **(**mapType)(unsafe.Pointer(&imap))
+ mt := **(**mapType)(unsafe.Pointer(&imap))
mt.string = &s
// gccgo uses a different hash
@@ -1684,7 +1705,7 @@ func FuncOf(in, out []Type, variadic bool) Type {
// Look in cache.
funcLookupCache.RLock()
for _, t := range funcLookupCache.m[hash] {
- if haveIdenticalUnderlyingType(&ft.rtype, t) {
+ if haveIdenticalUnderlyingType(&ft.rtype, t, true) {
funcLookupCache.RUnlock()
return t
}
@@ -1698,7 +1719,7 @@ func FuncOf(in, out []Type, variadic bool) Type {
funcLookupCache.m = make(map[uint32][]*rtype)
}
for _, t := range funcLookupCache.m[hash] {
- if haveIdenticalUnderlyingType(&ft.rtype, t) {
+ if haveIdenticalUnderlyingType(&ft.rtype, t, true) {
return t
}
}
@@ -1885,12 +1906,13 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
gcPtr = unsafe.Pointer(&gc[0])
}
- b := new(rtype)
- b.align = int8(maxAlign)
- b.fieldAlign = uint8(maxAlign)
- b.size = size
- b.kind = kind
- b.gc = gcPtr
+ b := &rtype{
+ align: int8(maxAlign),
+ fieldAlign: uint8(maxAlign),
+ size: size,
+ kind: kind,
+ gc: gcPtr,
+ }
s := "bucket(" + *ktyp.string + "," + *etyp.string + ")"
b.string = &s
return b
@@ -2002,8 +2024,7 @@ func SliceOf(t Type) Type {
// Make a slice type.
var islice interface{} = ([]unsafe.Pointer)(nil)
prototype := *(**sliceType)(unsafe.Pointer(&islice))
- slice := new(sliceType)
- *slice = *prototype
+ slice := *prototype
slice.string = &s
// gccgo uses a different hash.
@@ -2061,6 +2082,7 @@ func StructOf(fields []StructField) Type {
hasPtr = false // records whether at least one struct-field is a pointer
)
+ lastzero := uintptr(0)
repr = append(repr, "struct {"...)
for i, field := range fields {
if field.Type == nil {
@@ -2138,9 +2160,22 @@ func StructOf(fields []StructField) Type {
}
size = f.offset + ft.size
+ if ft.size == 0 {
+ lastzero = size
+ }
+
fs[i] = f
}
+ if size > 0 && lastzero == size {
+ // This is a non-zero sized struct that ends in a
+ // zero-sized field. We add an extra byte of padding,
+ // to ensure that taking the address of the final
+ // zero-sized field can't manufacture a pointer to the
+ // next object in the heap. See issue 9401.
+ size++
+ }
+
if len(fs) > 0 {
repr = append(repr, ' ')
}
@@ -2162,7 +2197,7 @@ func StructOf(fields []StructField) Type {
structLookupCache.RLock()
for _, st := range structLookupCache.m[hash] {
t := st.common()
- if haveIdenticalUnderlyingType(&typ.rtype, t) {
+ if haveIdenticalUnderlyingType(&typ.rtype, t, true) {
structLookupCache.RUnlock()
return t
}
@@ -2179,7 +2214,7 @@ func StructOf(fields []StructField) Type {
}
for _, st := range structLookupCache.m[hash] {
t := st.common()
- if haveIdenticalUnderlyingType(&typ.rtype, t) {
+ if haveIdenticalUnderlyingType(&typ.rtype, t, true) {
return t
}
}
@@ -2295,8 +2330,7 @@ func ArrayOf(count int, elem Type) Type {
// Make an array type.
var iarray interface{} = [1]unsafe.Pointer{}
prototype := *(**arrayType)(unsafe.Pointer(&iarray))
- array := new(arrayType)
- *array = *prototype
+ array := *prototype
array.string = &s
// gccgo uses a different hash.
diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go
index 1d18876..1b4c540 100644
--- a/libgo/go/reflect/value.go
+++ b/libgo/go/reflect/value.go
@@ -2113,14 +2113,14 @@ func convertOp(dst, src *rtype) func(Value, Type) Value {
}
// dst and src have same underlying type.
- if haveIdenticalUnderlyingType(dst, src) {
+ if haveIdenticalUnderlyingType(dst, src, false) {
return cvtDirect
}
// dst and src are unnamed pointer types with same underlying base type.
if dst.Kind() == Ptr && dst.Name() == "" &&
src.Kind() == Ptr && src.Name() == "" &&
- haveIdenticalUnderlyingType(dst.Elem().common(), src.Elem().common()) {
+ haveIdenticalUnderlyingType(dst.Elem().common(), src.Elem().common(), false) {
return cvtDirect
}