diff --git a/src/reflect/value.go b/src/reflect/value.go index 43c0c7e6..1188deb5 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -14,6 +14,10 @@ type valueFlags uint8 const ( valueFlagIndirect valueFlags = 1 << iota valueFlagExported + valueFlagEmbedRO + valueFlagStickyRO + + valueFlagRO = valueFlagEmbedRO | valueFlagStickyRO ) type Value struct { @@ -36,6 +40,16 @@ func (v Value) isExported() bool { return v.flags&valueFlagExported != 0 } +func (v Value) isRO() bool { + return v.flags&(valueFlagRO) != 0 +} + +func (v Value) checkRO() { + if v.isRO() { + panic("reflect: value is not settable") + } +} + func Indirect(v Value) Value { if v.Kind() != Ptr { return v @@ -210,7 +224,7 @@ func (v Value) IsValid() bool { } func (v Value) CanInterface() bool { - return v.isExported() + return v.isExported() && !v.isRO() } func (v Value) CanAddr() bool { @@ -268,7 +282,7 @@ func (v Value) UnsafeAddr() uintptr { } func (v Value) CanSet() bool { - return v.flags&(valueFlagExported|valueFlagIndirect) == valueFlagExported|valueFlagIndirect + return v.flags&(valueFlagExported|valueFlagIndirect|valueFlagRO) == valueFlagExported|valueFlagIndirect } func (v Value) Bool() bool { @@ -668,11 +682,22 @@ func (v Value) Field(i int) Value { panic(&ValueError{Method: "Field", Kind: v.Kind()}) } structField := v.typecode.rawField(i) - flags := v.flags + + // Copy flags but clear EmbedRO; we're not an embedded field anymore + flags := v.flags & ^valueFlagEmbedRO + if structField.PkgPath != "" { - // The fact that PkgPath is present means that this field is not - // exported. + // No PkgPath => not exported. + // Clear exported flag even if the parent was exported. flags &^= valueFlagExported + + // Update the RO flag + if structField.Anonymous { + // Embedded field + flags |= valueFlagEmbedRO + } else { + flags |= valueFlagStickyRO + } } else { // Parent field may not have been exported but we are flags |= valueFlagExported @@ -1437,7 +1462,7 @@ func Zero(typ Type) Value { return Value{ typecode: typ.(*rawType), value: nil, - flags: valueFlagExported, + flags: valueFlagExported | valueFlagRO, } } @@ -1445,14 +1470,14 @@ func Zero(typ Type) Value { return Value{ typecode: typ.(*rawType), value: unsafe.Pointer(zerobuffer), - flags: valueFlagExported, + flags: valueFlagExported | valueFlagRO, } } return Value{ typecode: typ.(*rawType), value: alloc(typ.Size(), nil), - flags: valueFlagExported, + flags: valueFlagExported | valueFlagRO, } } @@ -1546,6 +1571,10 @@ func Copy(dst, src Value) int { dstbuf, dstlen := buflen(dst) srcbuf, srclen := buflen(src) + if srclen > 0 { + dst.checkRO() + } + return sliceCopy(dstbuf, srcbuf, dstlen, srclen, dst.typecode.elem().Size()) }