Commit 9bbb07dd authored by Russ Cox's avatar Russ Cox

[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: 's avatarRobert Griesemer <gri@golang.org>
parent 43c70943
...@@ -74,7 +74,13 @@ func widstruct(errtype *Type, t *Type, o int64, flag int) int64 { ...@@ -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) { ...@@ -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: ...@@ -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 { ...@@ -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) { ...@@ -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) { ...@@ -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 { ...@@ -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) { ...@@ -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) { ...@@ -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 ...@@ -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) { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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) { ...@@ -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 { ...@@ -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 { ...@@ -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) { ...@@ -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 { ...@@ -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 { ...@@ -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
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment