diff --git a/src/cmd/compile/internal/escape/expr.go b/src/cmd/compile/internal/escape/expr.go index 62afb5b928..ced90a47bc 100644 --- a/src/cmd/compile/internal/escape/expr.go +++ b/src/cmd/compile/internal/escape/expr.go @@ -30,7 +30,7 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) { base.Pos = lno }() - if k.derefs >= 0 && !n.Type().HasPointers() { + if k.derefs >= 0 && !n.Type().IsUntyped() && !n.Type().HasPointers() { k.dst = &e.blankLoc } diff --git a/src/cmd/compile/internal/types/size.go b/src/cmd/compile/internal/types/size.go index aeeca90746..a47a26da74 100644 --- a/src/cmd/compile/internal/types/size.go +++ b/src/cmd/compile/internal/types/size.go @@ -630,17 +630,23 @@ func ResumeCheckSize() { // PtrDataSize returns the length in bytes of the prefix of t // containing pointer data. Anything after this offset is scalar data. +// +// PtrDataSize is only defined for actual Go types. It's an error to +// use it on compiler-internal types (e.g., TSSA, TRESULTS). func PtrDataSize(t *Type) int64 { - if !t.HasPointers() { - return 0 - } - switch t.Kind() { - case TPTR, - TUNSAFEPTR, - TFUNC, - TCHAN, - TMAP: + case TBOOL, TINT8, TUINT8, TINT16, TUINT16, TINT32, + TUINT32, TINT64, TUINT64, TINT, TUINT, + TUINTPTR, TCOMPLEX64, TCOMPLEX128, TFLOAT32, TFLOAT64: + return 0 + + case TPTR: + if t.Elem().NotInHeap() { + return 0 + } + return int64(PtrSize) + + case TUNSAFEPTR, TFUNC, TCHAN, TMAP: return int64(PtrSize) case TSTRING: @@ -654,24 +660,32 @@ func PtrDataSize(t *Type) int64 { return 2 * int64(PtrSize) case TSLICE: + if t.Elem().NotInHeap() { + return 0 + } // struct { byte *array; uintgo len; uintgo cap; } return int64(PtrSize) case TARRAY: - // haspointers already eliminated t.NumElem() == 0. - return (t.NumElem()-1)*t.Elem().width + PtrDataSize(t.Elem()) + if t.NumElem() == 0 { + return 0 + } + // t.NumElem() > 0 + size := PtrDataSize(t.Elem()) + if size == 0 { + return 0 + } + return (t.NumElem()-1)*t.Elem().Size() + size case TSTRUCT: - // Find the last field that has pointers. - var lastPtrField *Field + // Find the last field that has pointers, if any. fs := t.Fields().Slice() for i := len(fs) - 1; i >= 0; i-- { - if fs[i].Type.HasPointers() { - lastPtrField = fs[i] - break + if size := PtrDataSize(fs[i].Type); size > 0 { + return fs[i].Offset + size } } - return lastPtrField.Offset + PtrDataSize(lastPtrField.Type) + return 0 default: base.Fatalf("PtrDataSize: unexpected type, %v", t) diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go index 6070e15868..dafd76c79a 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -1681,43 +1681,7 @@ func (t *Type) IsUntyped() bool { // HasPointers reports whether t contains a heap pointer. // Note that this function ignores pointers to go:notinheap types. func (t *Type) HasPointers() bool { - switch t.kind { - case TINT, TUINT, TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64, - TUINT64, TUINTPTR, TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128, TBOOL, TSSA: - return false - - case TARRAY: - if t.NumElem() == 0 { // empty array has no pointers - return false - } - return t.Elem().HasPointers() - - case TSTRUCT: - for _, t1 := range t.Fields().Slice() { - if t1.Type.HasPointers() { - return true - } - } - return false - - case TPTR, TSLICE: - return !t.Elem().NotInHeap() - - case TTUPLE: - ttup := t.extra.(*Tuple) - return ttup.first.HasPointers() || ttup.second.HasPointers() - - case TRESULTS: - types := t.extra.(*Results).Types - for _, et := range types { - if et.HasPointers() { - return true - } - } - return false - } - - return true + return PtrDataSize(t) > 0 } // Tie returns 'T' if t is a concrete type,