// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// liveness tests with inlining disabled.
// see also live2.go.
packagemain
funcprintnl()
//go:noescape
funcprintpointer(**int)
//go:noescape
funcprintintpointer(*int)
//go:noescape
funcprintstringpointer(*string)
//go:noescape
funcprintstring(string)
//go:noescape
funcprintbytepointer(*byte)
funcprintint(int)
funcf1(){
varx*int
printpointer(&x)// ERROR "live at call to printpointer: x$"
printpointer(&x)// ERROR "live at call to printpointer: x$"
}
funcf2(bbool){
ifb{
printint(0)// nothing live here
return
}
varx*int
printpointer(&x)// ERROR "live at call to printpointer: x$"
printpointer(&x)// ERROR "live at call to printpointer: x$"
}
funcf3(b1,b2bool){
// Because x and y are ambiguously live, they appear
// live throughout the function, to avoid being poisoned
// in GODEBUG=gcdead=1 mode.
printint(0)// ERROR "live at call to printint: x y$"
ifb1==false{
printint(0)// ERROR "live at call to printint: x y$"
return
}
ifb2{
varx*int
printpointer(&x)// ERROR "live at call to printpointer: x y$"
printpointer(&x)// ERROR "live at call to printpointer: x y$"
}else{
vary*int
printpointer(&y)// ERROR "live at call to printpointer: x y$"
printpointer(&y)// ERROR "live at call to printpointer: x y$"
}
printint(0)// ERROR "f3: x \(type \*int\) is ambiguously live$" "f3: y \(type \*int\) is ambiguously live$" "live at call to printint: x y$"
}
// The old algorithm treated x as live on all code that
// could flow to a return statement, so it included the
// function entry and code above the declaration of x
// but would not include an indirect use of x in an infinite loop.
// Check that these cases are handled correctly.
funcf4(b1,b2bool){// x not live here
ifb2{
printint(0)// x not live here
return
}
varz**int
x:=new(int)
*x=42
z=&x
printint(**z)// ERROR "live at call to printint: x$"
ifb2{
printint(1)// x not live here
return
}
for{
printint(**z)// ERROR "live at call to printint: x$"
}
}
funcf5(b1bool){
varz**int
ifb1{
x:=new(int)
*x=42
z=&x
}else{
y:=new(int)
*y=54
z=&y
}
printint(**z)// ERROR "f5: x \(type \*int\) is ambiguously live$" "f5: y \(type \*int\) is ambiguously live$" "live at call to printint: x y$"
}
// confusion about the _ result used to cause spurious "live at entry to f6: _".
funcf6()(_,ystring){
y="hello"
return
}
// confusion about addressed results used to cause "live at entry to f7: x".
funcf7()(xstring){
_=&x
x="hello"
return
}
// ignoring block returns used to cause "live at entry to f8: x, y".
funcf8()(x,ystring){
returng8()
}
funcg8()(string,string)
// ignoring block assignments used to cause "live at entry to f9: x"
// issue 7205
vari9interface{}
funcf9()bool{
g8()
x:=i9
returnx!=interface{}(99.0i)// ERROR "live at call to convT2E: x.data x.type$"
}
// liveness formerly confused by UNDEF followed by RET,
// leading to "live at entry to f10: ~r1" (unnamed result).
funcf10()string{
panic(1)
}
// liveness formerly confused by select, thinking runtime.selectgo
// can return to next instruction; it always jumps elsewhere.
// note that you have to use at least two cases in the select
// to get a true select; smaller selects compile to optimized helper functions.
varcchan*int
varbbool
// this used to have a spurious "live at entry to f11a: ~r0"
funcf11a()*int{
select{// ERROR "live at call to newselect: autotmp_[0-9]+$" "live at call to selectgo: autotmp_[0-9]+$"
case<-c:// ERROR "live at call to selectrecv: autotmp_[0-9]+$"
returnnil
case<-c:// ERROR "live at call to selectrecv: autotmp_[0-9]+$"
returnnil
}
}
funcf11b()*int{
p:=new(int)
ifb{
// At this point p is dead: the code here cannot
// get to the bottom of the function.
// This used to have a spurious "live at call to printint: p".
printint(1)// nothing live here!
select{// ERROR "live at call to newselect: autotmp_[0-9]+$" "live at call to selectgo: autotmp_[0-9]+$"
case<-c:// ERROR "live at call to selectrecv: autotmp_[0-9]+$"
returnnil
case<-c:// ERROR "live at call to selectrecv: autotmp_[0-9]+$"
returnnil
}
}
println(*p)
returnnil
}
varsink*int
funcf11c()*int{
p:=new(int)
sink=p// prevent stack allocation, otherwise p is rematerializeable
ifb{
// Unlike previous, the cases in this select fall through,
// so we can get to the println, so p is not dead.
printint(1)// ERROR "live at call to printint: p$"
select{// ERROR "live at call to newselect: autotmp_[0-9]+ p$" "live at call to selectgo: autotmp_[0-9]+ p$"
case<-c:// ERROR "live at call to selectrecv: autotmp_[0-9]+ p$"
case<-c:// ERROR "live at call to selectrecv: autotmp_[0-9]+ p$"
}
}
println(*p)
returnnil
}
// similarly, select{} does not fall through.
// this used to have a spurious "live at entry to f12: ~r0".
funcf12()*int{
ifb{
select{}
}else{
returnnil
}
}
// incorrectly placed VARDEF annotations can cause missing liveness annotations.
// this used to be missing the fact that s is live during the call to g13 (because it is
// needed for the call to h13).
funcf13(){
s:=g14()
s=h13(s,g13(s))// ERROR "live at call to g13: s.ptr$"
}
funcg13(string)string
funch13(string,string)string
// more incorrectly placed VARDEF.
funcf14(){
x:=g14()
printstringpointer(&x)// ERROR "live at call to printstringpointer: x$"
}
funcg14()string
funcf15(){
varxstring
_=&x
x=g15()// ERROR "live at call to g15: x$"
printstring(x)// ERROR "live at call to printstring: x$"
}
funcg15()string
// Checking that various temporaries do not persist or cause
// ambiguously live values that must be zeroed.
// The exact temporary names are inconsequential but we are
// trying to check that there is only one at any given site,
// and also that none show up in "ambiguously live" messages.
varmmap[string]int
funcf16(){
ifb{
delete(m,"hi")// ERROR "live at call to mapdelete: autotmp_[0-9]+$"
}
delete(m,"hi")// ERROR "live at call to mapdelete: autotmp_[0-9]+$"
delete(m,"hi")// ERROR "live at call to mapdelete: autotmp_[0-9]+$"
}
varm2smap[string]*byte
varm2map[[2]string]*byte
varx2[2]string
varbp*byte
funcf17a(){
// value temporary only
ifb{
m2[x2]=nil// ERROR "live at call to mapassign1: autotmp_[0-9]+$"
}
m2[x2]=nil// ERROR "live at call to mapassign1: autotmp_[0-9]+$"
m2[x2]=nil// ERROR "live at call to mapassign1: autotmp_[0-9]+$"
}
funcf17b(){
// key temporary only
ifb{
m2s["x"]=bp// ERROR "live at call to mapassign1: autotmp_[0-9]+$"
}
m2s["x"]=bp// ERROR "live at call to mapassign1: autotmp_[0-9]+$"
m2s["x"]=bp// ERROR "live at call to mapassign1: autotmp_[0-9]+$"
}
funcf17c(){
// key and value temporaries
ifb{
m2s["x"]=nil// ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
}
m2s["x"]=nil// ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
m2s["x"]=nil// ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
}
funcg18()[2]string
funcf18(){
// key temporary for mapaccess.
// temporary introduced by orderexpr.
varz*byte
ifb{
z=m2[g18()]// ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
}
z=m2[g18()]// ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
z=m2[g18()]// ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
printbytepointer(z)
}
varchchan*byte
funcf19(){
// dest temporary for channel receive.
varz*byte
ifb{
z=<-ch// ERROR "live at call to chanrecv1: autotmp_[0-9]+$"
}
z=<-ch// ERROR "live at call to chanrecv1: autotmp_[0-9]+$"
z=<-ch// ERROR "live at call to chanrecv1: autotmp_[0-9]+$"
printbytepointer(z)
}
funcf20(){
// src temporary for channel send
ifb{
ch<-nil// ERROR "live at call to chansend1: autotmp_[0-9]+$"
}
ch<-nil// ERROR "live at call to chansend1: autotmp_[0-9]+$"
ch<-nil// ERROR "live at call to chansend1: autotmp_[0-9]+$"
}
funcf21(){
// key temporary for mapaccess using array literal key.
varz*byte
ifb{
z=m2[[2]string{"x","y"}]// ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
}
z=m2[[2]string{"x","y"}]// ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
z=m2[[2]string{"x","y"}]// ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
printbytepointer(z)
}
funcf23(){
// key temporary for two-result map access using array literal key.
varz*byte
varokbool
ifb{
z,ok=m2[[2]string{"x","y"}]// ERROR "live at call to mapaccess2: autotmp_[0-9]+$"
}
z,ok=m2[[2]string{"x","y"}]// ERROR "live at call to mapaccess2: autotmp_[0-9]+$"
z,ok=m2[[2]string{"x","y"}]// ERROR "live at call to mapaccess2: autotmp_[0-9]+$"
printbytepointer(z)
print(ok)
}
funcf24(){
// key temporary for map access using array literal key.
// value temporary too.
ifb{
m2[[2]string{"x","y"}]=nil// ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
}
m2[[2]string{"x","y"}]=nil// ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
m2[[2]string{"x","y"}]=nil// ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
}
// defer should not cause spurious ambiguously live variables
funcf25(bbool){
deferg25()
ifb{
return
}
varxstring
_=&x
x=g15()// ERROR "live at call to g15: x$"
printstring(x)// ERROR "live at call to printstring: x$"
}// ERROR "live at call to deferreturn: x$"
funcg25()
// non-escaping ... slices passed to function call should die on return,
// so that the temporaries do not stack and do not cause ambiguously
// live variables.
funcf26(bbool){
ifb{
print26((*int)(nil),(*int)(nil),(*int)(nil))// ERROR "live at call to print26: autotmp_[0-9]+$"
}
print26((*int)(nil),(*int)(nil),(*int)(nil))// ERROR "live at call to print26: autotmp_[0-9]+$"
print26((*int)(nil),(*int)(nil),(*int)(nil))// ERROR "live at call to print26: autotmp_[0-9]+$"
printnl()
}
//go:noescape
funcprint26(...interface{})
// non-escaping closures passed to function call should die on return
funcf27(bbool){
x:=0
ifb{
call27(func(){x++})// ERROR "live at call to call27: autotmp_[0-9]+$"
}
call27(func(){x++})// ERROR "live at call to call27: autotmp_[0-9]+$"
call27(func(){x++})// ERROR "live at call to call27: autotmp_[0-9]+$"
printnl()
}
// but defer does escape to later execution in the function
funcf27defer(bbool){
x:=0
ifb{
defercall27(func(){x++})// ERROR "live at call to deferproc: autotmp_[0-9]+$" "live at call to deferreturn: autotmp_[0-9]+$"
}
defercall27(func(){x++})// ERROR "f27defer: autotmp_[0-9]+ \(type struct { F uintptr; x \*int }\) is ambiguously live$" "live at call to deferproc: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to deferreturn: autotmp_[0-9]+ autotmp_[0-9]+$"
printnl()// ERROR "live at call to printnl: autotmp_[0-9]+ autotmp_[0-9]+$"
}// ERROR "live at call to deferreturn: autotmp_[0-9]+ autotmp_[0-9]+$"
// and newproc (go) escapes to the heap
funcf27go(bbool){
x:=0
ifb{
gocall27(func(){x++})// ERROR "live at call to newobject: &x$" "live at call to newproc: &x$"
}
gocall27(func(){x++})// ERROR "live at call to newobject: &x$"
printnl()
}
//go:noescape
funccall27(func())
// concatstring slice should die on return
vars1,s2,s3,s4,s5,s6,s7,s8,s9,s10string
funcf28(bbool){
ifb{
printstring(s1+s2+s3+s4+s5+s6+s7+s8+s9+s10)// ERROR "live at call to concatstrings: autotmp_[0-9]+$" "live at call to printstring: autotmp_[0-9]+$"
}
printstring(s1+s2+s3+s4+s5+s6+s7+s8+s9+s10)// ERROR "live at call to concatstrings: autotmp_[0-9]+$" "live at call to printstring: autotmp_[0-9]+$"
printstring(s1+s2+s3+s4+s5+s6+s7+s8+s9+s10)// ERROR "live at call to concatstrings: autotmp_[0-9]+$" "live at call to printstring: autotmp_[0-9]+$"
}
// map iterator should die on end of range loop
funcf29(bbool){
ifb{
fork:=rangem{// ERROR "live at call to mapiterinit: autotmp_[0-9]+$" "live at call to mapiternext: autotmp_[0-9]+$"
printstring(k)// ERROR "live at call to printstring: autotmp_[0-9]+$"
}
}
fork:=rangem{// ERROR "live at call to mapiterinit: autotmp_[0-9]+$" "live at call to mapiternext: autotmp_[0-9]+$"
printstring(k)// ERROR "live at call to printstring: autotmp_[0-9]+$"
}
fork:=rangem{// ERROR "live at call to mapiterinit: autotmp_[0-9]+$" "live at call to mapiternext: autotmp_[0-9]+$"
printstring(k)// ERROR "live at call to printstring: autotmp_[0-9]+$"
}
}
// copy of array of pointers should die at end of range loop
varptrarr[10]*int
funcf30(bbool){
// two live temps during print(p):
// the copy of ptrarr and the internal iterator pointer.
ifb{
for_,p:=rangeptrarr{
printintpointer(p)// ERROR "live at call to printintpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
}
}
for_,p:=rangeptrarr{
printintpointer(p)// ERROR "live at call to printintpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
}
for_,p:=rangeptrarr{
printintpointer(p)// ERROR "live at call to printintpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
}
}
// conversion to interface should not leave temporary behind
funcf31(b1,b2,b3bool){
ifb1{
g31("a")// ERROR "live at call to convT2E: autotmp_[0-9]+$" "live at call to g31: autotmp_[0-9]+$"
}
ifb2{
h31("b")// ERROR "live at call to convT2E: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to h31: autotmp_[0-9]+$" "live at call to newobject: autotmp_[0-9]+$"
}
ifb3{
panic("asdf")// ERROR "live at call to convT2E: autotmp_[0-9]+$" "live at call to gopanic: autotmp_[0-9]+$"
}
print(b3)
}
funcg31(interface{})
funch31(...interface{})
// non-escaping partial functions passed to function call should die on return
typeT32int
func(t*T32)Inc(){// ERROR "live at entry to \(\*T32\).Inc: t$"
*t++
}
vart32T32
funcf32(bbool){
ifb{
call32(t32.Inc)// ERROR "live at call to call32: autotmp_[0-9]+$"
}
call32(t32.Inc)// ERROR "live at call to call32: autotmp_[0-9]+$"
call32(t32.Inc)// ERROR "live at call to call32: autotmp_[0-9]+$"
}
//go:noescape
funccall32(func())
// temporaries introduced during if conditions and && || expressions
// should die once the condition has been acted upon.
varm33map[interface{}]int
funcf33(){
ifm33[nil]==0{// ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
printnl()
return
}else{
printnl()
}
printnl()
}
funcf34(){
ifm33[nil]==0{// ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
printnl()
return
}
printnl()
}
funcf35(){
ifm33[nil]==0&&m33[nil]==0{// ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
printnl()
return
}
printnl()
}
funcf36(){
ifm33[nil]==0||m33[nil]==0{// ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
printnl()
return
}
printnl()
}
funcf37(){
if(m33[nil]==0||m33[nil]==0)&&m33[nil]==0{// ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
printnl()
return
}
printnl()
}
// select temps should disappear in the case bodies
varc38chanstring
funcfc38()chanstring
funcfi38(int)*string
funcfb38()*bool
funcf38(bbool){
// we don't care what temps are printed on the lines with output.
// we care that the println lines have no live variables
// and therefore no output.
ifb{
select{// ERROR "live at call to newselect: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectgo: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
case<-fc38():// ERROR "live at call to selectrecv: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
printnl()
casefc38()<-*fi38(1):// ERROR "live at call to fc38: autotmp_[0-9]+$" "live at call to fi38: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectsend: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
printnl()
case*fi38(2)=<-fc38():// ERROR "live at call to fc38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to fi38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectrecv: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
printnl()
case*fi38(3),*fb38()=<-fc38():// ERROR "live at call to fb38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to fc38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to fi38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectrecv2: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
printnl()
}
printnl()
}
printnl()
}
// issue 8097: mishandling of x = x during return.
funcf39()(x[]int){
x=[]int{1}
printnl()// ERROR "live at call to printnl: autotmp_[0-9]+$"
returnx
}
funcf39a()(x[]int){
x=[]int{1}
printnl()// ERROR "live at call to printnl: autotmp_[0-9]+$"