dst = &e.theSink
}
- case ODOT: // treat "dst.x = src" as "dst = src"
+ case ODOT: // treat "dst.x = src" as "dst = src"
escassign(e, dst.Left, src)
return
ODOTMETH,
// treat recv.meth as a value with recv in it, only happens in ODEFER and OPROC
// iface.method already leaks iface in esccall, no need to put in extra ODOTINTER edge here
- ODOTTYPE,
ODOTTYPE2,
OSLICE,
OSLICE3,
// Conversions, field access, slice all preserve the input value.
escassign(e, dst, src.Left)
+ case ODOTTYPE:
+ if src.Type != nil && !haspointers(src.Type) {
+ break
+ }
+ escassign(e, dst, src.Left)
+
case OAPPEND:
// Append returns first argument.
// Subsequent arguments are already leaked because they are operands to append.
// finding an OADDR just means we're following the upstream of a dereference,
// so this address doesn't leak (yet).
// If level == 0, it means the /value/ of this node can reach the root of this flood.
-// so if this node is an OADDR, it's argument should be marked as escaping iff
-// it's currfn/e->loopdepth are different from the flood's root.
-// Once an object has been moved to the heap, all of it's upstream should be considered
+// so if this node is an OADDR, its argument should be marked as escaping iff
+// its currfn/e->loopdepth are different from the flood's root.
+// Once an object has been moved to the heap, all of its upstream should be considered
// escaping to the global scope.
func escflood(e *EscState, dst *Node) {
switch dst.Op {
T1: *(x.(*T1)), // ERROR "&T2 literal escapes to heap"
}
}
+
+func dotTypeEscape2() { // #13805
+ {
+ i := 0
+ var v int
+ var x interface{} = i // ERROR "i does not escape"
+ *(&v) = x.(int) // ERROR "&v does not escape"
+ }
+ {
+ i := 0
+ var x interface{} = i // ERROR "i does not escape"
+ sink = x.(int) // ERROR "x.\(int\) escapes to heap"
+
+ }
+ {
+ i := 0 // ERROR "moved to heap: i"
+ var x interface{} = &i // ERROR "&i escapes to heap"
+ sink = x.(*int) // ERROR "x.\(\*int\) escapes to heap"
+ }
+}