summaryrefslogtreecommitdiff
path: root/libgo/go/reflect
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2019-01-15 20:32:39 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2019-01-15 20:32:39 +0000
commit6a0c8e77f289a5c2e1b1ad0f2c8a5c5105f599a6 (patch)
treeed17062ac88ccb7fdf858eb98d80b5880065061a /libgo/go/reflect
parenta81a6d58367e63f3c7314eb793002e5feb379428 (diff)
compiler, runtime: panic on uncomparable map key, even if map is empty
This ports https://golang.org/cl/155918 from the master repo. runtime: panic on uncomparable map key, even if map is empty Reorg map flags a bit so we don't need any extra space for the extra flag. This is a pre-req for updating libgo to the Go 1.12beta2 release. Reviewed-on: https://go-review.googlesource.com/c/157858 From-SVN: r267950
Diffstat (limited to 'libgo/go/reflect')
-rw-r--r--libgo/go/reflect/type.go58
1 files changed, 42 insertions, 16 deletions
diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go
index da7796f3703..e4a9326d083 100644
--- a/libgo/go/reflect/type.go
+++ b/libgo/go/reflect/type.go
@@ -347,16 +347,13 @@ type interfaceType struct {
// mapType represents a map type.
type mapType struct {
rtype
- key *rtype // map key type
- elem *rtype // map element (value) type
- bucket *rtype // internal bucket structure
- keysize uint8 // size of key slot
- indirectkey uint8 // store ptr to key instead of key itself
- valuesize uint8 // size of value slot
- indirectvalue uint8 // store ptr to value instead of value itself
- bucketsize uint16 // size of bucket
- reflexivekey bool // true if k==k for all keys
- needkeyupdate bool // true if we need to update key on an overwrite
+ key *rtype // map key type
+ elem *rtype // map element (value) type
+ bucket *rtype // internal bucket structure
+ keysize uint8 // size of key slot
+ valuesize uint8 // size of value slot
+ bucketsize uint16 // size of bucket
+ flags uint32
}
// ptrType represents a pointer type.
@@ -1506,6 +1503,8 @@ func MapOf(key, elem Type) Type {
s := "map[" + *ktyp.string + "]" + *etyp.string
// Make a map type.
+ // Note: flag values must match those used in the TMAP case
+ // in ../cmd/compile/internal/gc/reflect.go:dtypesym.
var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil)
mt := **(**mapType)(unsafe.Pointer(&imap))
mt.string = &s
@@ -1520,23 +1519,29 @@ func MapOf(key, elem Type) Type {
mt.ptrToThis = nil
mt.bucket = bucketOf(ktyp, etyp)
+ mt.flags = 0
if ktyp.size > maxKeySize {
mt.keysize = uint8(ptrSize)
- mt.indirectkey = 1
+ mt.flags |= 1 // indirect key
} else {
mt.keysize = uint8(ktyp.size)
- mt.indirectkey = 0
}
if etyp.size > maxValSize {
mt.valuesize = uint8(ptrSize)
- mt.indirectvalue = 1
+ mt.flags |= 2 // indirect value
} else {
mt.valuesize = uint8(etyp.size)
- mt.indirectvalue = 0
}
mt.bucketsize = uint16(mt.bucket.size)
- mt.reflexivekey = isReflexive(ktyp)
- mt.needkeyupdate = needKeyUpdate(ktyp)
+ if isReflexive(ktyp) {
+ mt.flags |= 4
+ }
+ if needKeyUpdate(ktyp) {
+ mt.flags |= 8
+ }
+ if hashMightPanic(ktyp) {
+ mt.flags |= 16
+ }
// Canonicalize before storing in lookupCache
ti := toType(&mt.rtype)
@@ -1715,6 +1720,27 @@ func needKeyUpdate(t *rtype) bool {
}
}
+// hashMightPanic reports whether the hash of a map key of type t might panic.
+func hashMightPanic(t *rtype) bool {
+ switch t.Kind() {
+ case Interface:
+ return true
+ case Array:
+ tt := (*arrayType)(unsafe.Pointer(t))
+ return hashMightPanic(tt.elem)
+ case Struct:
+ tt := (*structType)(unsafe.Pointer(t))
+ for _, f := range tt.fields {
+ if hashMightPanic(f.typ) {
+ return true
+ }
+ }
+ return false
+ default:
+ return false
+ }
+}
+
// Make sure these routines stay in sync with ../../runtime/map.go!
// These types exist only for GC, so we only fill out GC relevant info.
// Currently, that's just size and the GC program. We also fill in string