From 2d1c0332598c77097d53a1c2d564b12dcd644810 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Tue, 2 Jan 2018 09:43:41 -0800 Subject: [PATCH] reflect: let StructOf define unexported fields This was missing from the original StructOf CL because I couldn't think of a use for it. Now I can: even with types used entirely by reflect, unexported fields can be set using UnsafeAddr. Change-Id: I5e7e3d81d16e8817cdd69d85796ce33930ef523b Reviewed-on: https://go-review.googlesource.com/c/go/+/85661 Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- doc/go1.14.html | 13 +++++++++++++ src/reflect/all_test.go | 23 ++++++++--------------- src/reflect/type.go | 19 +++++++++++-------- 3 files changed, 32 insertions(+), 23 deletions(-) diff --git a/doc/go1.14.html b/doc/go1.14.html index 525a1421f7d8f..e68cca56df1e3 100644 --- a/doc/go1.14.html +++ b/doc/go1.14.html @@ -115,6 +115,19 @@

Core library

+
+ +
reflect
+
+

+ StructOf now + supports creating struct types with unexported fields, by + setting the PkgPath field in + a StructField element. +

+ +
+
runtime

diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index fbb6feb0d98f2..7c5dd59aa78ca 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -4733,17 +4733,14 @@ func TestStructOfExportRules(t *testing.T) { mustPanic: true, }, { - field: StructField{Name: "s2", Type: TypeOf(int(0)), PkgPath: "other/pkg"}, - mustPanic: true, + field: StructField{Name: "s2", Type: TypeOf(int(0)), PkgPath: "other/pkg"}, }, { - field: StructField{Name: "s2", Type: TypeOf(int(0)), PkgPath: "other/pkg"}, - mustPanic: true, + field: StructField{Name: "s2", Type: TypeOf(int(0)), PkgPath: "other/pkg"}, }, { - field: StructField{Name: "S", Type: TypeOf(S1{})}, - mustPanic: false, - exported: true, + field: StructField{Name: "S", Type: TypeOf(S1{})}, + exported: true, }, { field: StructField{Name: "S", Type: TypeOf((*S1)(nil))}, @@ -4774,20 +4771,16 @@ func TestStructOfExportRules(t *testing.T) { mustPanic: true, }, { - field: StructField{Name: "s", Type: TypeOf(S1{}), PkgPath: "other/pkg"}, - mustPanic: true, // TODO(sbinet): creating a name with a package path + field: StructField{Name: "s", Type: TypeOf(S1{}), PkgPath: "other/pkg"}, }, { - field: StructField{Name: "s", Type: TypeOf((*S1)(nil)), PkgPath: "other/pkg"}, - mustPanic: true, // TODO(sbinet): creating a name with a package path + field: StructField{Name: "s", Type: TypeOf((*S1)(nil)), PkgPath: "other/pkg"}, }, { - field: StructField{Name: "s", Type: TypeOf(s2{}), PkgPath: "other/pkg"}, - mustPanic: true, // TODO(sbinet): creating a name with a package path + field: StructField{Name: "s", Type: TypeOf(s2{}), PkgPath: "other/pkg"}, }, { - field: StructField{Name: "s", Type: TypeOf((*s2)(nil)), PkgPath: "other/pkg"}, - mustPanic: true, // TODO(sbinet): creating a name with a package path + field: StructField{Name: "s", Type: TypeOf((*s2)(nil)), PkgPath: "other/pkg"}, }, { field: StructField{Name: "", Type: TypeOf(ΦType{})}, diff --git a/src/reflect/type.go b/src/reflect/type.go index 2cf912cf54e8b..f1f8ba93a440a 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -2731,15 +2731,18 @@ func StructOf(fields []StructField) Type { } func runtimeStructField(field StructField) structField { - if field.PkgPath != "" { - panic("reflect.StructOf: StructOf does not allow unexported fields") + if field.Anonymous && field.PkgPath != "" { + panic("reflect.StructOf: field \"" + field.Name + "\" is anonymous but has PkgPath set") } - // Best-effort check for misuse. - // Since PkgPath is empty, not much harm done if Unicode lowercase slips through. - c := field.Name[0] - if 'a' <= c && c <= 'z' || c == '_' { - panic("reflect.StructOf: field \"" + field.Name + "\" is unexported but missing PkgPath") + exported := field.PkgPath == "" + if exported { + // Best-effort check for misuse. + // Since this field will be treated as exported, not much harm done if Unicode lowercase slips through. + c := field.Name[0] + if 'a' <= c && c <= 'z' || c == '_' { + panic("reflect.StructOf: field \"" + field.Name + "\" is unexported but missing PkgPath") + } } offsetEmbed := uintptr(0) @@ -2749,7 +2752,7 @@ func runtimeStructField(field StructField) structField { resolveReflectType(field.Type.common()) // install in runtime return structField{ - name: newName(field.Name, string(field.Tag), true), + name: newName(field.Name, string(field.Tag), exported), typ: field.Type.common(), offsetEmbed: offsetEmbed, }