diff --git a/cmp/options.go b/cmp/options.go index 3e66674..d029da3 100644 --- a/cmp/options.go +++ b/cmp/options.go @@ -431,7 +431,7 @@ func AllowUnexported(types ...any) Option { m := make(map[reflect.Type]bool) for _, typ := range types { t := reflect.TypeOf(typ) - if t.Kind() != reflect.Struct { + if t == nil || t.Kind() != reflect.Struct { panic(fmt.Sprintf("invalid struct type: %T", typ)) } m[t] = true diff --git a/cmp/options_test.go b/cmp/options_test.go index b58f56e..e5e3576 100644 --- a/cmp/options_test.go +++ b/cmp/options_test.go @@ -214,3 +214,19 @@ func TestOptionPanic(t *testing.T) { }) } } + +// TestAllowUnexportedNilPanic asserts that AllowUnexported(nil) panics with +// the same descriptive message as other invalid inputs rather than crashing +// with a nil pointer dereference. TestOptionPanic cannot cover this case +// because it invokes the option functions through reflection, which cannot +// represent a bare nil argument. +func TestAllowUnexportedNilPanic(t *testing.T) { + var gotPanic any + func() { + defer func() { gotPanic = recover() }() + AllowUnexported(nil) + }() + if s, ok := gotPanic.(string); !ok || !strings.Contains(s, "invalid struct type") { + t.Fatalf("panic = %v (type %T), want string containing %q", gotPanic, gotPanic, "invalid struct type") + } +}