compiler, reflect: fix struct field names for embedded aliases
authorIan Lance Taylor <ian@gcc.gnu.org>
Thu, 14 Sep 2017 03:48:51 +0000 (03:48 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Thu, 14 Sep 2017 03:48:51 +0000 (03:48 +0000)
    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

gcc/go/gofrontend/MERGE
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/types.cc
libgo/go/reflect/all_test.go
libgo/go/reflect/type.go
libgo/go/reflect/value.go

index c4600de4cc8410c91be8c1e1f830a14a58437469..a905f583859972c02359377a49f3b259441176a4 100644 (file)
@@ -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.
index 6f9c1c96c3f510b2e87f6013cc6dc55862e059c1..1e4d90647b896b22df24b05566c4534c0cc913f9 100644 (file)
@@ -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.
index cdf1f402834042c90993ccfb554ab988bfd2f01f..e91922c1cac8d21a8c1d2bdc4631f0fe9c814d54 100644 (file)
@@ -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);
index 3686167ed42cff52e1104337f8010b0db919f069..6ac33526774c0c4a7d3ae515cda89165b66c1a6f 100644 (file)
@@ -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 {
index 3ae0f182b3add839925ad2777a563a84eda364a8..97b986a7bba81b2ad77a03a27c4242f7aa9993c1 100644 (file)
@@ -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)
                }
        }
 }
index 1b4c5407e57c5a3909f2f6b71761efa0f16f14c8..208bb2f4c01b2a61da10e3759f8204aab45032c5 100644 (file)
@@ -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}
 }