mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.typealias] cmd/compile, reflect: fix struct field names for embedded byte, rune
Will also fix type aliases. Fixes #17766. For #18130. Change-Id: I9e1584d47128782152e06abd0a30ef423d5c30d2 Reviewed-on: https://go-review.googlesource.com/35732 Run-TryBot: Russ Cox <rsc@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
43c7094386
commit
9bbb07ddec
8 changed files with 85 additions and 62 deletions
|
|
@ -74,7 +74,13 @@ func widstruct(errtype *Type, t *Type, o int64, flag int) int64 {
|
||||||
lastzero = o
|
lastzero = o
|
||||||
}
|
}
|
||||||
o += w
|
o += w
|
||||||
if o >= Thearch.MAXWIDTH {
|
maxwidth := Thearch.MAXWIDTH
|
||||||
|
// On 32-bit systems, reflect tables impose an additional constraint
|
||||||
|
// that each field start offset must fit in 31 bits.
|
||||||
|
if maxwidth < 1<<32 {
|
||||||
|
maxwidth = 1<<31 - 1
|
||||||
|
}
|
||||||
|
if o >= maxwidth {
|
||||||
yyerror("type %L too large", errtype)
|
yyerror("type %L too large", errtype)
|
||||||
o = 8 // small but nonzero
|
o = 8 // small but nonzero
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -511,7 +511,7 @@ func isExportedField(ft *Field) (bool, *Pkg) {
|
||||||
// dnameField dumps a reflect.name for a struct field.
|
// dnameField dumps a reflect.name for a struct field.
|
||||||
func dnameField(s *Sym, ot int, spkg *Pkg, ft *Field) int {
|
func dnameField(s *Sym, ot int, spkg *Pkg, ft *Field) int {
|
||||||
var name string
|
var name string
|
||||||
if ft.Sym != nil && ft.Embedded == 0 {
|
if ft.Sym != nil {
|
||||||
name = ft.Sym.Name
|
name = ft.Sym.Name
|
||||||
}
|
}
|
||||||
isExported, fpkg := isExportedField(ft)
|
isExported, fpkg := isExportedField(ft)
|
||||||
|
|
@ -1345,7 +1345,14 @@ ok:
|
||||||
// ../../../../runtime/type.go:/structField
|
// ../../../../runtime/type.go:/structField
|
||||||
ot = dnameField(s, ot, pkg, f)
|
ot = dnameField(s, ot, pkg, f)
|
||||||
ot = dsymptr(s, ot, dtypesym(f.Type), 0)
|
ot = dsymptr(s, ot, dtypesym(f.Type), 0)
|
||||||
ot = duintptr(s, ot, uint64(f.Offset))
|
offsetAnon := uint64(f.Offset) << 1
|
||||||
|
if offsetAnon>>1 != uint64(f.Offset) {
|
||||||
|
Fatalf("%v: bad field offset for %s", t, f.Sym.Name)
|
||||||
|
}
|
||||||
|
if f.Embedded != 0 {
|
||||||
|
offsetAnon |= 1
|
||||||
|
}
|
||||||
|
ot = duintptr(s, ot, offsetAnon)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -255,7 +255,7 @@ func decodetypeStructFieldType(s *Symbol, i int) *Symbol {
|
||||||
|
|
||||||
func decodetypeStructFieldOffs(arch *sys.Arch, s *Symbol, i int) int64 {
|
func decodetypeStructFieldOffs(arch *sys.Arch, s *Symbol, i int) int64 {
|
||||||
off := decodetypeStructFieldArrayOff(s, i)
|
off := decodetypeStructFieldArrayOff(s, i)
|
||||||
return int64(decodeInuxi(arch, s.P[off+2*SysArch.PtrSize:], SysArch.IntSize))
|
return int64(decodeInuxi(arch, s.P[off+2*SysArch.PtrSize:], SysArch.IntSize) >> 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InterfaceType.methods.length
|
// InterfaceType.methods.length
|
||||||
|
|
|
||||||
|
|
@ -4265,7 +4265,7 @@ func TestStructOfExportRules(t *testing.T) {
|
||||||
field := typ.Field(0)
|
field := typ.Field(0)
|
||||||
n := field.Name
|
n := field.Name
|
||||||
if n == "" {
|
if n == "" {
|
||||||
n = field.Type.Name()
|
panic("field.Name must not be empty")
|
||||||
}
|
}
|
||||||
exported := isExported(n)
|
exported := isExported(n)
|
||||||
if exported != test.exported {
|
if exported != test.exported {
|
||||||
|
|
@ -5984,3 +5984,20 @@ func TestUnaddressableField(t *testing.T) {
|
||||||
lv.Set(rv)
|
lv.Set(rv)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Talias1 struct {
|
||||||
|
byte
|
||||||
|
uint8
|
||||||
|
int
|
||||||
|
int32
|
||||||
|
rune
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAliasNames(t *testing.T) {
|
||||||
|
t1 := Talias1{byte: 1, uint8: 2, int: 3, int32: 4, rune: 5}
|
||||||
|
out := fmt.Sprintf("%#v", t1)
|
||||||
|
want := "reflect_test.Talias1{byte:0x1, uint8:0x2, int:3, int32:4, rune:5}"
|
||||||
|
if out != want {
|
||||||
|
t.Errorf("Talias1 print:\nhave: %s\nwant: %s", out, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -417,9 +417,17 @@ type sliceType struct {
|
||||||
|
|
||||||
// Struct field
|
// Struct field
|
||||||
type structField struct {
|
type structField struct {
|
||||||
name name // name is empty for embedded fields
|
name name // name is always non-empty
|
||||||
typ *rtype // type of field
|
typ *rtype // type of field
|
||||||
offset uintptr // byte offset of field within struct
|
offsetAnon uintptr // byte offset of field<<1 | isAnonymous
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *structField) offset() uintptr {
|
||||||
|
return f.offsetAnon >> 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *structField) anon() bool {
|
||||||
|
return f.offsetAnon&1 != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// structType represents a struct type.
|
// structType represents a struct type.
|
||||||
|
|
@ -1215,16 +1223,8 @@ func (t *structType) Field(i int) (f StructField) {
|
||||||
}
|
}
|
||||||
p := &t.fields[i]
|
p := &t.fields[i]
|
||||||
f.Type = toType(p.typ)
|
f.Type = toType(p.typ)
|
||||||
if name := p.name.name(); name != "" {
|
f.Name = p.name.name()
|
||||||
f.Name = name
|
f.Anonymous = p.anon()
|
||||||
} else {
|
|
||||||
t := f.Type
|
|
||||||
if t.Kind() == Ptr {
|
|
||||||
t = t.Elem()
|
|
||||||
}
|
|
||||||
f.Name = t.Name()
|
|
||||||
f.Anonymous = true
|
|
||||||
}
|
|
||||||
if !p.name.isExported() {
|
if !p.name.isExported() {
|
||||||
f.PkgPath = p.name.pkgPath()
|
f.PkgPath = p.name.pkgPath()
|
||||||
if f.PkgPath == "" {
|
if f.PkgPath == "" {
|
||||||
|
|
@ -1234,7 +1234,7 @@ func (t *structType) Field(i int) (f StructField) {
|
||||||
if tag := p.name.tag(); tag != "" {
|
if tag := p.name.tag(); tag != "" {
|
||||||
f.Tag = StructTag(tag)
|
f.Tag = StructTag(tag)
|
||||||
}
|
}
|
||||||
f.Offset = p.offset
|
f.Offset = p.offset()
|
||||||
|
|
||||||
// NOTE(rsc): This is the only allocation in the interface
|
// NOTE(rsc): This is the only allocation in the interface
|
||||||
// presented by a reflect.Type. It would be nice to avoid,
|
// presented by a reflect.Type. It would be nice to avoid,
|
||||||
|
|
@ -1321,19 +1321,15 @@ func (t *structType) FieldByNameFunc(match func(string) bool) (result StructFiel
|
||||||
visited[t] = true
|
visited[t] = true
|
||||||
for i := range t.fields {
|
for i := range t.fields {
|
||||||
f := &t.fields[i]
|
f := &t.fields[i]
|
||||||
// Find name and type for field f.
|
// Find name and (for anonymous field) type for field f.
|
||||||
var fname string
|
fname := f.name.name()
|
||||||
var ntyp *rtype
|
var ntyp *rtype
|
||||||
if name := f.name.name(); name != "" {
|
if f.anon() {
|
||||||
fname = name
|
|
||||||
} else {
|
|
||||||
// Anonymous field of type T or *T.
|
// Anonymous field of type T or *T.
|
||||||
// Name taken from type.
|
|
||||||
ntyp = f.typ
|
ntyp = f.typ
|
||||||
if ntyp.Kind() == Ptr {
|
if ntyp.Kind() == Ptr {
|
||||||
ntyp = ntyp.Elem().common()
|
ntyp = ntyp.Elem().common()
|
||||||
}
|
}
|
||||||
fname = ntyp.Name()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Does it match?
|
// Does it match?
|
||||||
|
|
@ -1390,14 +1386,12 @@ func (t *structType) FieldByName(name string) (f StructField, present bool) {
|
||||||
if name != "" {
|
if name != "" {
|
||||||
for i := range t.fields {
|
for i := range t.fields {
|
||||||
tf := &t.fields[i]
|
tf := &t.fields[i]
|
||||||
tfname := tf.name.name()
|
if tf.name.name() == name {
|
||||||
if tfname == "" {
|
|
||||||
hasAnon = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if tfname == name {
|
|
||||||
return t.Field(i), true
|
return t.Field(i), true
|
||||||
}
|
}
|
||||||
|
if tf.anon() {
|
||||||
|
hasAnon = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !hasAnon {
|
if !hasAnon {
|
||||||
|
|
@ -1694,7 +1688,7 @@ func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool {
|
||||||
if cmpTags && tf.name.tag() != vf.name.tag() {
|
if cmpTags && tf.name.tag() != vf.name.tag() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if tf.offset != vf.offset {
|
if tf.offsetAnon != vf.offsetAnon {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !tf.name.isExported() {
|
if !tf.name.isExported() {
|
||||||
|
|
@ -2418,13 +2412,11 @@ func StructOf(fields []StructField) Type {
|
||||||
hasPtr = true
|
hasPtr = true
|
||||||
}
|
}
|
||||||
|
|
||||||
name := ""
|
|
||||||
// Update string and hash
|
// Update string and hash
|
||||||
if f.name.nameLen() > 0 {
|
name := f.name.name()
|
||||||
hash = fnv1(hash, []byte(f.name.name())...)
|
hash = fnv1(hash, []byte(name)...)
|
||||||
repr = append(repr, (" " + f.name.name())...)
|
repr = append(repr, (" " + name)...)
|
||||||
name = f.name.name()
|
if f.anon() {
|
||||||
} else {
|
|
||||||
// Embedded field
|
// Embedded field
|
||||||
if f.typ.Kind() == Ptr {
|
if f.typ.Kind() == Ptr {
|
||||||
// Embedded ** and *interface{} are illegal
|
// Embedded ** and *interface{} are illegal
|
||||||
|
|
@ -2432,11 +2424,7 @@ func StructOf(fields []StructField) Type {
|
||||||
if k := elem.Kind(); k == Ptr || k == Interface {
|
if k := elem.Kind(); k == Ptr || k == Interface {
|
||||||
panic("reflect.StructOf: illegal anonymous field type " + ft.String())
|
panic("reflect.StructOf: illegal anonymous field type " + ft.String())
|
||||||
}
|
}
|
||||||
name = elem.String()
|
|
||||||
} else {
|
|
||||||
name = ft.String()
|
|
||||||
}
|
}
|
||||||
// TODO(sbinet) check for syntactically impossible type names?
|
|
||||||
|
|
||||||
switch f.typ.Kind() {
|
switch f.typ.Kind() {
|
||||||
case Interface:
|
case Interface:
|
||||||
|
|
@ -2568,11 +2556,12 @@ func StructOf(fields []StructField) Type {
|
||||||
comparable = comparable && (ft.alg.equal != nil)
|
comparable = comparable && (ft.alg.equal != nil)
|
||||||
hashable = hashable && (ft.alg.hash != nil)
|
hashable = hashable && (ft.alg.hash != nil)
|
||||||
|
|
||||||
f.offset = align(size, uintptr(ft.align))
|
offset := align(size, uintptr(ft.align))
|
||||||
if ft.align > typalign {
|
if ft.align > typalign {
|
||||||
typalign = ft.align
|
typalign = ft.align
|
||||||
}
|
}
|
||||||
size = f.offset + ft.size
|
size = offset + ft.size
|
||||||
|
f.offsetAnon |= offset << 1
|
||||||
|
|
||||||
if ft.size == 0 {
|
if ft.size == 0 {
|
||||||
lastzero = size
|
lastzero = size
|
||||||
|
|
@ -2764,7 +2753,7 @@ func StructOf(fields []StructField) Type {
|
||||||
typ.alg.hash = func(p unsafe.Pointer, seed uintptr) uintptr {
|
typ.alg.hash = func(p unsafe.Pointer, seed uintptr) uintptr {
|
||||||
o := seed
|
o := seed
|
||||||
for _, ft := range typ.fields {
|
for _, ft := range typ.fields {
|
||||||
pi := unsafe.Pointer(uintptr(p) + ft.offset)
|
pi := unsafe.Pointer(uintptr(p) + ft.offset())
|
||||||
o = ft.typ.alg.hash(pi, o)
|
o = ft.typ.alg.hash(pi, o)
|
||||||
}
|
}
|
||||||
return o
|
return o
|
||||||
|
|
@ -2774,8 +2763,8 @@ func StructOf(fields []StructField) Type {
|
||||||
if comparable {
|
if comparable {
|
||||||
typ.alg.equal = func(p, q unsafe.Pointer) bool {
|
typ.alg.equal = func(p, q unsafe.Pointer) bool {
|
||||||
for _, ft := range typ.fields {
|
for _, ft := range typ.fields {
|
||||||
pi := unsafe.Pointer(uintptr(p) + ft.offset)
|
pi := unsafe.Pointer(uintptr(p) + ft.offset())
|
||||||
qi := unsafe.Pointer(uintptr(q) + ft.offset)
|
qi := unsafe.Pointer(uintptr(q) + ft.offset())
|
||||||
if !ft.typ.alg.equal(pi, qi) {
|
if !ft.typ.alg.equal(pi, qi) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -2808,16 +2797,16 @@ func runtimeStructField(field StructField) structField {
|
||||||
panic("reflect.StructOf: field \"" + field.Name + "\" is unexported but missing PkgPath")
|
panic("reflect.StructOf: field \"" + field.Name + "\" is unexported but missing PkgPath")
|
||||||
}
|
}
|
||||||
|
|
||||||
name := field.Name
|
offsetAnon := uintptr(0)
|
||||||
if field.Anonymous {
|
if field.Anonymous {
|
||||||
name = ""
|
offsetAnon |= 1
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveReflectType(field.Type.common()) // install in runtime
|
resolveReflectType(field.Type.common()) // install in runtime
|
||||||
return structField{
|
return structField{
|
||||||
name: newName(name, string(field.Tag), "", true),
|
name: newName(field.Name, string(field.Tag), "", true),
|
||||||
typ: field.Type.common(),
|
typ: field.Type.common(),
|
||||||
offset: 0,
|
offsetAnon: offsetAnon,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2840,7 +2829,7 @@ func typeptrdata(t *rtype) uintptr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f := st.fields[field]
|
f := st.fields[field]
|
||||||
return f.offset + f.typ.ptrdata
|
return f.offset() + f.typ.ptrdata
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic("reflect.typeptrdata: unexpected type, " + t.String())
|
panic("reflect.typeptrdata: unexpected type, " + t.String())
|
||||||
|
|
@ -3214,7 +3203,7 @@ func addTypeBits(bv *bitVector, offset uintptr, t *rtype) {
|
||||||
tt := (*structType)(unsafe.Pointer(t))
|
tt := (*structType)(unsafe.Pointer(t))
|
||||||
for i := range tt.fields {
|
for i := range tt.fields {
|
||||||
f := &tt.fields[i]
|
f := &tt.fields[i]
|
||||||
addTypeBits(bv, offset+f.offset, f.typ)
|
addTypeBits(bv, offset+f.offset(), f.typ)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -755,7 +755,7 @@ func (v Value) Field(i int) Value {
|
||||||
fl := v.flag&(flagStickyRO|flagIndir|flagAddr) | flag(typ.Kind())
|
fl := v.flag&(flagStickyRO|flagIndir|flagAddr) | flag(typ.Kind())
|
||||||
// Using an unexported field forces flagRO.
|
// Using an unexported field forces flagRO.
|
||||||
if !field.name.isExported() {
|
if !field.name.isExported() {
|
||||||
if field.name.name() == "" {
|
if field.anon() {
|
||||||
fl |= flagEmbedRO
|
fl |= flagEmbedRO
|
||||||
} else {
|
} else {
|
||||||
fl |= flagStickyRO
|
fl |= flagStickyRO
|
||||||
|
|
@ -766,7 +766,7 @@ func (v Value) Field(i int) Value {
|
||||||
// In the former case, we want v.ptr + offset.
|
// In the former case, we want v.ptr + offset.
|
||||||
// In the latter case, we must have field.offset = 0,
|
// In the latter case, we must have field.offset = 0,
|
||||||
// so v.ptr + field.offset is still okay.
|
// so v.ptr + field.offset is still okay.
|
||||||
ptr := unsafe.Pointer(uintptr(v.ptr) + field.offset)
|
ptr := unsafe.Pointer(uintptr(v.ptr) + field.offset())
|
||||||
return Value{typ, ptr, fl}
|
return Value{typ, ptr, fl}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -531,7 +531,7 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, f := range st.fields {
|
for _, f := range st.fields {
|
||||||
cgoCheckArg(f.typ, add(p, f.offset), true, top, msg)
|
cgoCheckArg(f.typ, add(p, f.offset()), true, top, msg)
|
||||||
}
|
}
|
||||||
case kindPtr, kindUnsafePointer:
|
case kindPtr, kindUnsafePointer:
|
||||||
if indir {
|
if indir {
|
||||||
|
|
|
||||||
|
|
@ -390,9 +390,13 @@ type ptrtype struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type structfield struct {
|
type structfield struct {
|
||||||
name name
|
name name
|
||||||
typ *_type
|
typ *_type
|
||||||
offset uintptr
|
offsetAnon uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *structfield) offset() uintptr {
|
||||||
|
return f.offsetAnon >> 1
|
||||||
}
|
}
|
||||||
|
|
||||||
type structtype struct {
|
type structtype struct {
|
||||||
|
|
@ -650,7 +654,7 @@ func typesEqual(t, v *_type) bool {
|
||||||
if tf.name.tag() != vf.name.tag() {
|
if tf.name.tag() != vf.name.tag() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if tf.offset != vf.offset {
|
if tf.offsetAnon != vf.offsetAnon {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue