From patchwork Thu Sep 14 03:48:54 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 813701 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-462100-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="iXwJJ5+M"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3xt4K52Tgcz9s7g for ; Thu, 14 Sep 2017 13:49:13 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; q= dns; s=default; b=RwTEr6zhCQihZMhOH+z0uijb/ExPSU9wu5+hSnXhL20Mty tY4YX625T2QWWBg2Wmss3ciDNlqDcEaZPW/0xsAnSbqvlm+ZCrEKK+cLxuAS3qeG UlEUk3WRVkqmJwr/lbtja3Rbv3VlxhfA4SAmrIuYDGEaXhZzDjDLLVZ7TwiNc= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; s= default; bh=1+JBggdH7ATktN8HixokXwG62xU=; b=iXwJJ5+MSId0yZYGMDoG OaYPuulZ0tZP/AJ2+5kpWdNVBDV+PupAWS9G5leQvzFaoS32AcurKI8E4HFV5ZE5 U/xwFwCh6yjdETGVa43s4usg3uwTKM9zHziWdnM3p4FurMaC0PirRhZ+vRuS7iX4 i9/Hzlr+2Brqv0DgGCRVUoc= Received: (qmail 127105 invoked by alias); 14 Sep 2017 03:49:00 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 127082 invoked by uid 89); 14 Sep 2017 03:49:00 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-10.5 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, RCVD_IN_SORBS_SPAM, SPF_PASS autolearn=ham version=3.3.2 spammy=6367, comparable, seed, bloc X-HELO: mail-pg0-f45.google.com Received: from mail-pg0-f45.google.com (HELO mail-pg0-f45.google.com) (74.125.83.45) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 14 Sep 2017 03:48:57 +0000 Received: by mail-pg0-f45.google.com with SMTP id d8so4141294pgt.4 for ; Wed, 13 Sep 2017 20:48:57 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=A8Nrv16RRGGrySwvqzJ2oK2Dg0RL0ovqmqrFCdfvW3E=; b=VtZ8Pc4O4PWE6E/elTjM/kG5ejAFRaLQ3ilXSudNb9e3NWh1PHmU4AyadvUgLB36/i fZZo8QXtTclqZJVzjUHZ8UfW+kOg6TlAMvEQ/Xd5Uy0yp01FEmQo1/TE1EsgQBVmcqjp pP9y9GVTdDww8EJsFeNtEd8tLEIZLlhiC4MkRmL8wU1Q7W3VNXlISi+HY8CyTLSbLRXy 0zaFnKF/TR2DQP8wKIW65+6DAR0zuvNLGbavnmIIT1f23+QZ8rX/A2OPbLQUJzQWrpYk NgwfBAt4VGKoN+UOb0Kb3lFqG5LBor54VBjrPK7O2iaAI7P4GC3k4/MXsaIiU4YsGwVH dIcQ== X-Gm-Message-State: AHPjjUjMf9xTr7X652YfkopYbxi97QONX5bYoVkgfQLDDRcZsY7Aj2tx 4rfA0zsRRjtOBqx5y2fMfe0t+S2cP1uYR7WtAU7LjBFq X-Google-Smtp-Source: ADKCNb4ev0w6VzUuGxaApYpv7wmhJhvxSeBEt44ycGegFgiLIY/bLpSDxOJLqYTh73QuGcm8kFnIAMdpAjZ6vR7xidw= X-Received: by 10.98.86.216 with SMTP id h85mr20463663pfj.88.1505360935444; Wed, 13 Sep 2017 20:48:55 -0700 (PDT) MIME-Version: 1.0 Received: by 10.100.182.173 with HTTP; Wed, 13 Sep 2017 20:48:54 -0700 (PDT) From: Ian Lance Taylor Date: Wed, 13 Sep 2017 20:48:54 -0700 Message-ID: Subject: Go patch committed: Fix struct field names for embedded aliases To: gcc-patches , "gofrontend-dev@googlegroups.com" This patch to the Go frontend adds much of https://golang.org/cl/35731 and https://golang.org/cl/35732, patches to the gc toolchain, 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. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline. Ian Index: gcc/go/gofrontend/MERGE =================================================================== --- gcc/go/gofrontend/MERGE (revision 252745) +++ gcc/go/gofrontend/MERGE (working copy) @@ -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: gcc/go/gofrontend/expressions.cc =================================================================== --- gcc/go/gofrontend/expressions.cc (revision 251948) +++ gcc/go/gofrontend/expressions.cc (working copy) @@ -6044,35 +6044,46 @@ Binary_expression::do_get_backend(Transl { 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(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: gcc/go/gofrontend/types.cc =================================================================== --- gcc/go/gofrontend/types.cc (revision 252745) +++ gcc/go/gofrontend/types.cc (working copy) @@ -6372,7 +6372,7 @@ Struct_type::make_struct_type_descriptor "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* go 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* go } ++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: libgo/go/reflect/all_test.go =================================================================== --- libgo/go/reflect/all_test.go (revision 251948) +++ libgo/go/reflect/all_test.go (working copy) @@ -4184,50 +4184,58 @@ func TestStructOfExportRules(t *testing. 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. 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. 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: libgo/go/reflect/type.go =================================================================== --- libgo/go/reflect/type.go (revision 251948) +++ libgo/go/reflect/type.go (working copy) @@ -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 Str } 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(mat 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 st 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 *r 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 StructFiel } } + offsetAnon := uintptr(0) + if field.Anonymous { + offsetAnon |= 1 + } + var pkgPath *string if field.PkgPath != "" { s := field.PkgPath @@ -2212,11 +2213,11 @@ func runtimeStructField(field StructFiel } 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 u 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: libgo/go/reflect/value.go =================================================================== --- libgo/go/reflect/value.go (revision 251948) +++ libgo/go/reflect/value.go (working copy) @@ -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} }