aboutsummaryrefslogtreecommitdiff
path: root/libgo
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2017-09-14 03:48:51 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2017-09-14 03:48:51 +0000
commitce64a8b4a2334fd6982a21d1ab020a1108562f6b (patch)
tree83191e42d888f13aa922cfda85d4c7eafe051622 /libgo
parented52163bea1916404119f397e6f99a4b90477f37 (diff)
downloadgcc-ce64a8b4a2334fd6982a21d1ab020a1108562f6b.zip
gcc-ce64a8b4a2334fd6982a21d1ab020a1108562f6b.tar.gz
gcc-ce64a8b4a2334fd6982a21d1ab020a1108562f6b.tar.bz2
compiler, reflect: fix struct field names for embedded aliases
This adds much of https://golang.org/cl/35731 and https://golang.org/cl/35732 to the gofrontend code. This is a step toward updating libgo to the 1.9 release. The gofrontend already supports type aliases, and this is required for correct support of type aliases when used as embedded fields. The change to expressions.cc is to handle the << 1, used for the newly renamed offsetAnon field, in the constant context used for type descriptor initialization. Reviewed-on: https://go-review.googlesource.com/62710 From-SVN: r252746
Diffstat (limited to 'libgo')
-rw-r--r--libgo/go/reflect/all_test.go95
-rw-r--r--libgo/go/reflect/type.go83
-rw-r--r--libgo/go/reflect/value.go4
3 files changed, 89 insertions, 93 deletions
diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go
index 3686167..6ac3352 100644
--- a/libgo/go/reflect/all_test.go
+++ b/libgo/go/reflect/all_test.go
@@ -4184,50 +4184,58 @@ func TestStructOfExportRules(t *testing.T) {
f()
}
- for i, test := range []struct {
+ tests := []struct {
field StructField
mustPanic bool
exported bool
}{
{
- field: StructField{Name: "", Type: TypeOf(S1{})},
- mustPanic: false,
- exported: true,
+ field: StructField{Name: "S1", Anonymous: true, Type: TypeOf(S1{})},
+ exported: true,
},
{
- field: StructField{Name: "", Type: TypeOf((*S1)(nil))},
- mustPanic: false,
- exported: true,
+ field: StructField{Name: "S1", Anonymous: true, Type: TypeOf((*S1)(nil))},
+ exported: true,
},
{
- field: StructField{Name: "", Type: TypeOf(s2{})},
- mustPanic: false,
- exported: false,
+ field: StructField{Name: "s2", Anonymous: true, Type: TypeOf(s2{})},
+ mustPanic: true,
},
{
- field: StructField{Name: "", Type: TypeOf((*s2)(nil))},
- mustPanic: false,
- exported: false,
+ field: StructField{Name: "s2", Anonymous: true, Type: TypeOf((*s2)(nil))},
+ mustPanic: true,
},
{
- field: StructField{Name: "", Type: TypeOf(S1{}), PkgPath: "other/pkg"},
+ field: StructField{Name: "Name", Type: nil, PkgPath: ""},
mustPanic: true,
- exported: true,
},
{
- field: StructField{Name: "", Type: TypeOf((*S1)(nil)), PkgPath: "other/pkg"},
+ field: StructField{Name: "", Type: TypeOf(S1{}), PkgPath: ""},
+ mustPanic: true,
+ },
+ {
+ field: StructField{Name: "S1", Anonymous: true, Type: TypeOf(S1{}), PkgPath: "other/pkg"},
+ mustPanic: true,
+ },
+ {
+ field: StructField{Name: "S1", Anonymous: true, Type: TypeOf((*S1)(nil)), PkgPath: "other/pkg"},
+ mustPanic: true,
+ },
+ {
+ field: StructField{Name: "s2", Anonymous: true, Type: TypeOf(s2{}), PkgPath: "other/pkg"},
mustPanic: true,
- exported: true,
},
{
- field: StructField{Name: "", Type: TypeOf(s2{}), PkgPath: "other/pkg"},
+ field: StructField{Name: "s2", Anonymous: true, Type: TypeOf((*s2)(nil)), PkgPath: "other/pkg"},
mustPanic: true,
- exported: false,
},
{
- field: StructField{Name: "", Type: TypeOf((*s2)(nil)), 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"},
mustPanic: true,
- exported: false,
},
{
field: StructField{Name: "S", Type: TypeOf(S1{})},
@@ -4235,81 +4243,68 @@ func TestStructOfExportRules(t *testing.T) {
exported: true,
},
{
- field: StructField{Name: "S", Type: TypeOf((*S1)(nil))},
- mustPanic: false,
- exported: true,
+ field: StructField{Name: "S", Type: TypeOf((*S1)(nil))},
+ exported: true,
},
{
- field: StructField{Name: "S", Type: TypeOf(s2{})},
- mustPanic: false,
- exported: true,
+ field: StructField{Name: "S", Type: TypeOf(s2{})},
+ exported: true,
},
{
- field: StructField{Name: "S", Type: TypeOf((*s2)(nil))},
- mustPanic: false,
- exported: true,
+ field: StructField{Name: "S", Type: TypeOf((*s2)(nil))},
+ exported: true,
},
{
field: StructField{Name: "s", Type: TypeOf(S1{})},
mustPanic: true,
- exported: false,
},
{
field: StructField{Name: "s", Type: TypeOf((*S1)(nil))},
mustPanic: true,
- exported: false,
},
{
field: StructField{Name: "s", Type: TypeOf(s2{})},
mustPanic: true,
- exported: false,
},
{
field: StructField{Name: "s", Type: TypeOf((*s2)(nil))},
mustPanic: true,
- exported: false,
},
{
field: StructField{Name: "s", Type: TypeOf(S1{}), PkgPath: "other/pkg"},
mustPanic: true, // TODO(sbinet): creating a name with a package path
- exported: false,
},
{
field: StructField{Name: "s", Type: TypeOf((*S1)(nil)), PkgPath: "other/pkg"},
mustPanic: true, // TODO(sbinet): creating a name with a package path
- exported: false,
},
{
field: StructField{Name: "s", Type: TypeOf(s2{}), PkgPath: "other/pkg"},
mustPanic: true, // TODO(sbinet): creating a name with a package path
- exported: false,
},
{
field: StructField{Name: "s", Type: TypeOf((*s2)(nil)), PkgPath: "other/pkg"},
mustPanic: true, // TODO(sbinet): creating a name with a package path
- exported: false,
},
{
field: StructField{Name: "", Type: TypeOf(ΦType{})},
- mustPanic: false,
- exported: true,
+ mustPanic: true,
},
{
field: StructField{Name: "", Type: TypeOf(φType{})},
- mustPanic: false,
- exported: false,
+ mustPanic: true,
},
{
- field: StructField{Name: "Φ", Type: TypeOf(0)},
- mustPanic: false,
- exported: true,
+ field: StructField{Name: "Φ", Type: TypeOf(0)},
+ exported: true,
},
{
- field: StructField{Name: "φ", Type: TypeOf(0)},
- mustPanic: false,
- exported: false,
+ field: StructField{Name: "φ", Type: TypeOf(0)},
+ exported: false,
},
- } {
+ }
+
+ for i, test := range tests {
testPanic(i, test.mustPanic, func() {
typ := StructOf([]StructField{test.field})
if typ == nil {
@@ -4319,7 +4314,7 @@ func TestStructOfExportRules(t *testing.T) {
field := typ.Field(0)
n := field.Name
if n == "" {
- n = field.Type.Name()
+ panic("field.Name must not be empty")
}
exported := isExported(n)
if exported != test.exported {
diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go
index 3ae0f18..97b986a 100644
--- a/libgo/go/reflect/type.go
+++ b/libgo/go/reflect/type.go
@@ -370,11 +370,19 @@ type sliceType struct {
// Struct field
type structField struct {
- name *string // nil for embedded fields
- pkgPath *string // nil for exported Names; otherwise import path
- typ *rtype // type of field
- tag *string // nil if no tag
- offset uintptr // byte offset of field within struct
+ name *string // name is always non-empty
+ pkgPath *string // nil for exported Names; otherwise import path
+ typ *rtype // type of field
+ tag *string // nil if no tag
+ 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.
@@ -880,23 +888,15 @@ func (t *structType) Field(i int) (f StructField) {
}
p := &t.fields[i]
f.Type = toType(p.typ)
- if p.name != nil {
- f.Name = *p.name
- } else {
- t := f.Type
- if t.Kind() == Ptr {
- t = t.Elem()
- }
- f.Name = t.Name()
- f.Anonymous = true
- }
+ f.Name = *p.name
+ f.Anonymous = p.anon()
if p.pkgPath != nil {
f.PkgPath = *p.pkgPath
}
if p.tag != nil {
f.Tag = StructTag(*p.tag)
}
- f.Offset = p.offset
+ f.Offset = p.offset()
// NOTE(rsc): This is the only allocation in the interface
// presented by a reflect.Type. It would be nice to avoid,
@@ -984,18 +984,15 @@ func (t *structType) FieldByNameFunc(match func(string) bool) (result StructFiel
for i := range t.fields {
f := &t.fields[i]
// Find name and type for field f.
- var fname string
+ fname := *f.name
var ntyp *rtype
- if f.name != nil {
- fname = *f.name
- } else {
+ if f.anon() {
// Anonymous field of type T or *T.
// Name taken from type.
ntyp = f.typ
if ntyp.Kind() == Ptr {
ntyp = ntyp.Elem().common()
}
- fname = ntyp.Name()
}
// Does it match?
@@ -1053,13 +1050,12 @@ func (t *structType) FieldByName(name string) (f StructField, present bool) {
if name != "" {
for i := range t.fields {
tf := &t.fields[i]
- if tf.name == nil {
- hasAnon = true
- continue
- }
if *tf.name == name {
return t.Field(i), true
}
+ if tf.anon() {
+ hasAnon = true
+ }
}
}
if !hasAnon {
@@ -1390,7 +1386,7 @@ func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool {
if cmpTags && tf.tag != vf.tag && (tf.tag == nil || vf.tag == nil || *tf.tag != *vf.tag) {
return false
}
- if tf.offset != vf.offset {
+ if tf.offsetAnon != vf.offsetAnon {
return false
}
}
@@ -1946,11 +1942,10 @@ func StructOf(fields []StructField) Type {
hasPtr = true
}
- name := ""
// Update string and hash
+ name := *f.name
hash = (hash << 1) + ft.hash
- if f.name != nil {
- name = *f.name
+ if !f.anon() {
repr = append(repr, (" " + name)...)
} else {
// Embedded field
@@ -2009,11 +2004,12 @@ func StructOf(fields []StructField) Type {
comparable = comparable && (ft.equalfn != nil)
hashable = hashable && (ft.hashfn != nil)
- f.offset = align(size, uintptr(ft.fieldAlign))
+ offset := align(size, uintptr(ft.fieldAlign))
if int8(ft.fieldAlign) > typalign {
typalign = int8(ft.fieldAlign)
}
- size = f.offset + ft.size
+ size = offset + ft.size
+ f.offsetAnon |= offset << 1
if ft.size == 0 {
lastzero = size
@@ -2148,7 +2144,7 @@ func StructOf(fields []StructField) Type {
typ.hashfn = func(p unsafe.Pointer, seed uintptr) uintptr {
o := seed
for _, ft := range typ.fields {
- pi := unsafe.Pointer(uintptr(p) + ft.offset)
+ pi := unsafe.Pointer(uintptr(p) + ft.offset())
o = ft.typ.hashfn(pi, o)
}
return o
@@ -2160,8 +2156,8 @@ func StructOf(fields []StructField) Type {
if comparable {
typ.equalfn = func(p, q unsafe.Pointer) bool {
for _, ft := range typ.fields {
- pi := unsafe.Pointer(uintptr(p) + ft.offset)
- qi := unsafe.Pointer(uintptr(q) + ft.offset)
+ pi := unsafe.Pointer(uintptr(p) + ft.offset())
+ qi := unsafe.Pointer(uintptr(q) + ft.offset())
if !ft.typ.equalfn(pi, qi) {
return false
}
@@ -2196,6 +2192,11 @@ func runtimeStructField(field StructField) structField {
}
}
+ offsetAnon := uintptr(0)
+ if field.Anonymous {
+ offsetAnon |= 1
+ }
+
var pkgPath *string
if field.PkgPath != "" {
s := field.PkgPath
@@ -2212,11 +2213,11 @@ func runtimeStructField(field StructField) structField {
}
return structField{
- name: name,
- pkgPath: pkgPath,
- typ: field.Type.common(),
- tag: tag,
- offset: 0,
+ name: name,
+ pkgPath: pkgPath,
+ typ: field.Type.common(),
+ tag: tag,
+ offsetAnon: offsetAnon,
}
}
@@ -2239,7 +2240,7 @@ func typeptrdata(t *rtype) uintptr {
}
}
f := st.fields[field]
- return f.offset + f.typ.ptrdata
+ return f.offset() + f.typ.ptrdata
default:
panic("reflect.typeptrdata: unexpected type, " + t.String())
@@ -2513,7 +2514,7 @@ func addTypeBits(bv *bitVector, offset uintptr, t *rtype) {
tt := (*structType)(unsafe.Pointer(t))
for i := range tt.fields {
f := &tt.fields[i]
- addTypeBits(bv, offset+f.offset, f.typ)
+ addTypeBits(bv, offset+f.offset(), f.typ)
}
}
}
diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go
index 1b4c540..208bb2f 100644
--- a/libgo/go/reflect/value.go
+++ b/libgo/go/reflect/value.go
@@ -625,7 +625,7 @@ func (v Value) Field(i int) Value {
fl := v.flag&(flagStickyRO|flagIndir|flagAddr) | flag(typ.Kind())
// Using an unexported field forces flagRO.
if field.pkgPath != nil {
- if field.name == nil {
+ if field.anon() {
fl |= flagEmbedRO
} else {
fl |= flagStickyRO
@@ -636,7 +636,7 @@ func (v Value) Field(i int) Value {
// In the former case, we want v.ptr + offset.
// In the latter case, we must have field.offset = 0,
// 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}
}