diff options
| -rw-r--r-- | gcc/go/gofrontend/MERGE | 2 | ||||
| -rw-r--r-- | gcc/go/gofrontend/expressions.cc | 63 | ||||
| -rw-r--r-- | gcc/go/gofrontend/types.cc | 24 | ||||
| -rw-r--r-- | libgo/go/reflect/all_test.go | 95 | ||||
| -rw-r--r-- | libgo/go/reflect/type.go | 83 | ||||
| -rw-r--r-- | libgo/go/reflect/value.go | 4 |
6 files changed, 140 insertions, 131 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index c4600de..a905f58 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -8c6d9ff6f60b737d1e96c0dab0b4e67402bf3316 +b0a46c2cdb915ddc4a4e401af9ef6eb2bcd4d4ea The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 6f9c1c9..1e4d906 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -6044,35 +6044,46 @@ Binary_expression::do_get_backend(Translate_context* context) { go_assert(left_type->integer_type() != NULL); - mpz_t bitsval; int bits = left_type->integer_type()->bits(); - mpz_init_set_ui(bitsval, bits); - Bexpression* bits_expr = - gogo->backend()->integer_constant_expression(right_btype, bitsval); - Bexpression* compare = - gogo->backend()->binary_expression(OPERATOR_LT, - right, bits_expr, loc); - - Bexpression* zero_expr = - gogo->backend()->integer_constant_expression(left_btype, zero); - overflow = zero_expr; - Bfunction* bfn = context->function()->func_value()->get_decl(); - if (this->op_ == OPERATOR_RSHIFT - && !left_type->integer_type()->is_unsigned()) + + Numeric_constant nc; + unsigned long ul; + if (!this->right_->numeric_constant_value(&nc) + || nc.to_unsigned_long(&ul) != Numeric_constant::NC_UL_VALID + || ul >= static_cast<unsigned long>(bits)) { - Bexpression* neg_expr = - gogo->backend()->binary_expression(OPERATOR_LT, left, - zero_expr, loc); - Bexpression* neg_one_expr = - gogo->backend()->integer_constant_expression(left_btype, neg_one); - overflow = gogo->backend()->conditional_expression(bfn, - btype, neg_expr, - neg_one_expr, - zero_expr, loc); + mpz_t bitsval; + mpz_init_set_ui(bitsval, bits); + Bexpression* bits_expr = + gogo->backend()->integer_constant_expression(right_btype, bitsval); + Bexpression* compare = + gogo->backend()->binary_expression(OPERATOR_LT, + right, bits_expr, loc); + + Bexpression* zero_expr = + gogo->backend()->integer_constant_expression(left_btype, zero); + overflow = zero_expr; + Bfunction* bfn = context->function()->func_value()->get_decl(); + if (this->op_ == OPERATOR_RSHIFT + && !left_type->integer_type()->is_unsigned()) + { + Bexpression* neg_expr = + gogo->backend()->binary_expression(OPERATOR_LT, left, + zero_expr, loc); + Bexpression* neg_one_expr = + gogo->backend()->integer_constant_expression(left_btype, + neg_one); + overflow = gogo->backend()->conditional_expression(bfn, + btype, + neg_expr, + neg_one_expr, + zero_expr, + loc); + } + ret = gogo->backend()->conditional_expression(bfn, btype, compare, + ret, overflow, loc); + mpz_clear(bitsval); } - ret = gogo->backend()->conditional_expression(bfn, btype, compare, ret, - overflow, loc); - mpz_clear(bitsval); } // Add checks for division by zero and division overflow as needed. diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index cdf1f40..e91922c 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -6372,7 +6372,7 @@ Struct_type::make_struct_type_descriptor_type() "pkgPath", pointer_string_type, "typ", ptdt, "tag", pointer_string_type, - "offset", uintptr_type); + "offsetAnon", uintptr_type); Type* nsf = Type::make_builtin_named_type("structField", sf); Type* slice_type = Type::make_array_type(nsf, NULL); @@ -6429,14 +6429,9 @@ Struct_type::do_type_descriptor(Gogo* gogo, Named_type* name) Struct_field_list::const_iterator q = f->begin(); go_assert(q->is_field_name("name")); - if (pf->is_anonymous()) - fvals->push_back(Expression::make_nil(bloc)); - else - { - std::string n = Gogo::unpack_hidden_name(pf->field_name()); - Expression* s = Expression::make_string(n, bloc); - fvals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc)); - } + std::string n = Gogo::unpack_hidden_name(pf->field_name()); + Expression* s = Expression::make_string(n, bloc); + fvals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc)); ++q; go_assert(q->is_field_name("pkgPath")); @@ -6469,8 +6464,15 @@ Struct_type::do_type_descriptor(Gogo* gogo, Named_type* name) } ++q; - go_assert(q->is_field_name("offset")); - fvals->push_back(Expression::make_struct_field_offset(this, &*pf)); + go_assert(q->is_field_name("offsetAnon")); + Type* uintptr_type = Type::lookup_integer_type("uintptr"); + Expression* o = Expression::make_struct_field_offset(this, &*pf); + Expression* one = Expression::make_integer_ul(1, uintptr_type, bloc); + o = Expression::make_binary(OPERATOR_LSHIFT, o, one, bloc); + int av = pf->is_anonymous() ? 1 : 0; + Expression* anon = Expression::make_integer_ul(av, uintptr_type, bloc); + o = Expression::make_binary(OPERATOR_OR, o, anon, bloc); + fvals->push_back(o); Expression* v = Expression::make_struct_composite_literal(element_type, fvals, bloc); 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} } |
