unique: handle zero-size types

Fixes #69458

Change-Id: Ic7fda7f556522780b2819138dfc1277137398692
Reviewed-on: https://go-review.googlesource.com/c/go/+/613397
Reviewed-by: Carlos Amedee <carlos@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
This commit is contained in:
Cuong Manh Le 2024-09-16 23:58:40 +07:00 committed by Gopher Robot
parent aa06c94054
commit 2927aa10ab
2 changed files with 14 additions and 3 deletions

View File

@ -10,9 +10,11 @@ import (
"internal/weak"
"runtime"
"sync"
_ "unsafe"
"unsafe"
)
var zero uintptr
// Handle is a globally unique identity for some value of type T.
//
// Two handles compare equal exactly if the two values used to create the handles
@ -32,6 +34,9 @@ func (h Handle[T]) Value() T {
func Make[T comparable](value T) Handle[T] {
// Find the map for type T.
typ := abi.TypeFor[T]()
if typ.Size() == 0 {
return Handle[T]{(*T)(unsafe.Pointer(&zero))}
}
ma, ok := uniqueMaps.Load(typ)
if !ok {
// This is a good time to initialize cleanup, since we must go through

View File

@ -31,6 +31,7 @@ type testStruct struct {
z float64
b string
}
type testZeroSize struct{}
func TestHandle(t *testing.T) {
testHandle(t, testString("foo"))
@ -45,6 +46,7 @@ func TestHandle(t *testing.T) {
})
testHandle(t, testStruct{0.5, "184"})
testHandle(t, testEface("hello"))
testHandle(t, testZeroSize(struct{}{}))
}
func testHandle[T comparable](t *testing.T, value T) {
@ -65,15 +67,19 @@ func testHandle[T comparable](t *testing.T, value T) {
t.Error("v0 != v1")
}
drainMaps(t)
drainMaps[T](t)
checkMapsFor(t, value)
})
}
// drainMaps ensures that the internal maps are drained.
func drainMaps(t *testing.T) {
func drainMaps[T comparable](t *testing.T) {
t.Helper()
if unsafe.Sizeof(*(new(T))) == 0 {
return // zero-size types are not inserted.
}
wait := make(chan struct{}, 1)
// Set up a one-time notification for the next time the cleanup runs.