-8c6d9ff6f60b737d1e96c0dab0b4e67402bf3316
+b0a46c2cdb915ddc4a4e401af9ef6eb2bcd4d4ea
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
{
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.
"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);
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"));
}
++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);
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{})},
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 {
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 {
// 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.
}
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,
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?
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 {
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
}
}
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
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
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
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
}
}
}
+ offsetAnon := uintptr(0)
+ if field.Anonymous {
+ offsetAnon |= 1
+ }
+
var pkgPath *string
if field.PkgPath != "" {
s := field.PkgPath
}
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,
}
}
}
}
f := st.fields[field]
- return f.offset + f.typ.ptrdata
+ return f.offset() + f.typ.ptrdata
default:
panic("reflect.typeptrdata: unexpected type, " + t.String())
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)
}
}
}
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
// 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}
}