}
// Conversions from regular to go:notinheap are not allowed
- // (unless it's unsafe.Pointer). This is a runtime-specific
- // rule.
+ // (unless it's unsafe.Pointer). These are runtime-specific
+ // rules.
+ // (a) Disallow (*T) to (*U) where T is go:notinheap but U isn't.
if src.IsPtr() && dst.IsPtr() && dst.Elem().NotInHeap() && !src.Elem().NotInHeap() {
if why != nil {
*why = fmt.Sprintf(":\n\t%v is go:notinheap, but %v is not", dst.Elem(), src.Elem())
}
return 0
}
+ // (b) Disallow string to []T where T is go:notinheap.
+ if src.IsString() && dst.IsSlice() && dst.Elem().NotInHeap() && (dst.Elem().Etype == types.Bytetype.Etype || dst.Elem().Etype == types.Runetype.Etype) {
+ if why != nil {
+ *why = fmt.Sprintf(":\n\t%v is go:notinheap", dst.Elem())
+ }
+ return 0
+ }
// 1. src can be assigned to dst.
op := assignop(src, dst, why)
//go:notinheap
type t2 t1
+//go:notinheap
+type t3 byte
+
+//go:notinheap
+type t4 rune
+
var sink interface{}
func i() {
sink = new(t1) // no error
sink = (*t2)(new(t1)) // ERROR "cannot convert(.|\n)*t2 is go:notinheap"
sink = (*t2)(new(struct{ x int })) // ERROR "cannot convert(.|\n)*t2 is go:notinheap"
+ sink = []t3("foo") // ERROR "cannot convert(.|\n)*t3 is go:notinheap"
+ sink = []t4("bar") // ERROR "cannot convert(.|\n)*t4 is go:notinheap"
}