Source file test/inline.go

     1  // errorcheckwithauto -0 -m -d=inlfuncswithclosures=1
     2  
     3  //go:build !goexperiment.newinliner
     4  
     5  // Copyright 2015 The Go Authors. All rights reserved.
     6  // Use of this source code is governed by a BSD-style
     7  // license that can be found in the LICENSE file.
     8  
     9  // Test, using compiler diagnostic flags, that inlining is working.
    10  // Compiles but does not run.
    11  
    12  package foo
    13  
    14  import (
    15  	"errors"
    16  	"runtime"
    17  	"unsafe"
    18  )
    19  
    20  func add2(p *byte, n uintptr) *byte { // ERROR "can inline add2" "leaking param: p to result"
    21  	return (*byte)(add1(unsafe.Pointer(p), n)) // ERROR "inlining call to add1"
    22  }
    23  
    24  func add1(p unsafe.Pointer, x uintptr) unsafe.Pointer { // ERROR "can inline add1" "leaking param: p to result"
    25  	return unsafe.Pointer(uintptr(p) + x)
    26  }
    27  
    28  func f(x *byte) *byte { // ERROR "can inline f" "leaking param: x to result"
    29  	return add2(x, 1) // ERROR "inlining call to add2" "inlining call to add1"
    30  }
    31  
    32  //go:noinline
    33  func g(x int) int {
    34  	return x + 1
    35  }
    36  
    37  func h(x int) int { // ERROR "can inline h"
    38  	return x + 2
    39  }
    40  
    41  func i(x int) int { // ERROR "can inline i"
    42  	const y = 2
    43  	return x + y
    44  }
    45  
    46  func j(x int) int { // ERROR "can inline j"
    47  	switch {
    48  	case x > 0:
    49  		return x + 2
    50  	default:
    51  		return x + 1
    52  	}
    53  }
    54  
    55  func f2() int { // ERROR "can inline f2"
    56  	tmp1 := h
    57  	tmp2 := tmp1
    58  	return tmp2(0) // ERROR "inlining call to h"
    59  }
    60  
    61  var abc = errors.New("abc") // ERROR "inlining call to errors.New"
    62  
    63  var somethingWrong error
    64  
    65  // local closures can be inlined
    66  func l(x, y int) (int, int, error) { // ERROR "can inline l"
    67  	e := func(err error) (int, int, error) { // ERROR "can inline l.func1" "func literal does not escape" "leaking param: err to result"
    68  		return 0, 0, err
    69  	}
    70  	if x == y {
    71  		e(somethingWrong) // ERROR "inlining call to l.func1"
    72  	} else {
    73  		f := e
    74  		f(nil) // ERROR "inlining call to l.func1"
    75  	}
    76  	_ = e // prevent simple deadcode elimination after inlining
    77  	return y, x, nil
    78  }
    79  
    80  // any re-assignment prevents closure inlining
    81  func m() int {
    82  	foo := func() int { return 1 } // ERROR "can inline m.func1" "func literal does not escape"
    83  	x := foo()
    84  	foo = func() int { return 2 } // ERROR "can inline m.func2" "func literal does not escape"
    85  	return x + foo()
    86  }
    87  
    88  // address taking prevents closure inlining
    89  func n() int {
    90  	foo := func() int { return 1 } // ERROR "can inline n.func1" "func literal does not escape"
    91  	bar := &foo
    92  	x := (*bar)() + foo()
    93  	return x
    94  }
    95  
    96  // make sure assignment inside closure is detected
    97  func o() int {
    98  	foo := func() int { return 1 } // ERROR "can inline o.func1" "func literal does not escape"
    99  	func(x int) {                  // ERROR "can inline o.func2"
   100  		if x > 10 {
   101  			foo = func() int { return 2 } // ERROR "can inline o.func2"
   102  		}
   103  	}(11) // ERROR "func literal does not escape" "inlining call to o.func2"
   104  	return foo()
   105  }
   106  
   107  func p() int { // ERROR "can inline p"
   108  	return func() int { return 42 }() // ERROR "can inline p.func1" "inlining call to p.func1"
   109  }
   110  
   111  func q(x int) int { // ERROR "can inline q"
   112  	foo := func() int { return x * 2 } // ERROR "can inline q.func1" "func literal does not escape"
   113  	_ = foo                            // prevent simple deadcode elimination after inlining
   114  	return foo()                       // ERROR "inlining call to q.func1"
   115  }
   116  
   117  func r(z int) int {
   118  	foo := func(x int) int { // ERROR "can inline r.func1" "func literal does not escape"
   119  		return x + z
   120  	}
   121  	bar := func(x int) int { // ERROR "func literal does not escape" "can inline r.func2"
   122  		return x + func(y int) int { // ERROR "can inline r.func2.1" "can inline r.r.func2.func3"
   123  			return 2*y + x*z
   124  		}(x) // ERROR "inlining call to r.func2.1"
   125  	}
   126  	_, _ = foo, bar // prevent simple deadcode elimination after inlining
   127  
   128  	return foo(42) + bar(42) // ERROR "inlining call to r.func1" "inlining call to r.func2" "inlining call to r.r.func2.func3"
   129  }
   130  
   131  func s0(x int) int { // ERROR "can inline s0"
   132  	foo := func() { // ERROR "can inline s0.func1" "func literal does not escape"
   133  		x = x + 1
   134  	}
   135  	foo()   // ERROR "inlining call to s0.func1"
   136  	_ = foo // prevent simple deadcode elimination after inlining
   137  	return x
   138  }
   139  
   140  func s1(x int) int { // ERROR "can inline s1"
   141  	foo := func() int { // ERROR "can inline s1.func1" "func literal does not escape"
   142  		return x
   143  	}
   144  	x = x + 1
   145  	_ = foo      // prevent simple deadcode elimination after inlining
   146  	return foo() // ERROR "inlining call to s1.func1"
   147  }
   148  
   149  func switchBreak(x, y int) int { // ERROR "can inline switchBreak"
   150  	var n int
   151  	switch x {
   152  	case 0:
   153  		n = 1
   154  	Done:
   155  		switch y {
   156  		case 0:
   157  			n += 10
   158  			break Done
   159  		}
   160  		n = 2
   161  	}
   162  	return n
   163  }
   164  
   165  func switchType(x interface{}) int { // ERROR "can inline switchType" "x does not escape"
   166  	switch x.(type) {
   167  	case int:
   168  		return x.(int)
   169  	default:
   170  		return 0
   171  	}
   172  }
   173  
   174  // Test that switches on constant things, with constant cases, only cost anything for
   175  // the case that matches. See issue 50253.
   176  func switchConst1(p func(string)) { // ERROR "can inline switchConst" "p does not escape"
   177  	const c = 1
   178  	switch c {
   179  	case 0:
   180  		p("zero")
   181  	case 1:
   182  		p("one")
   183  	case 2:
   184  		p("two")
   185  	default:
   186  		p("other")
   187  	}
   188  }
   189  
   190  func switchConst2() string { // ERROR "can inline switchConst2"
   191  	switch runtime.GOOS {
   192  	case "linux":
   193  		return "Leenooks"
   194  	case "windows":
   195  		return "Windoze"
   196  	case "darwin":
   197  		return "MackBone"
   198  	case "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100":
   199  		return "Numbers"
   200  	default:
   201  		return "oh nose!"
   202  	}
   203  }
   204  func switchConst3() string { // ERROR "can inline switchConst3"
   205  	switch runtime.GOOS {
   206  	case "Linux":
   207  		panic("Linux")
   208  	case "Windows":
   209  		panic("Windows")
   210  	case "Darwin":
   211  		panic("Darwin")
   212  	case "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100":
   213  		panic("Numbers")
   214  	default:
   215  		return "oh nose!"
   216  	}
   217  }
   218  func switchConst4() { // ERROR "can inline switchConst4"
   219  	const intSize = 32 << (^uint(0) >> 63)
   220  	want := func() string { // ERROR "can inline switchConst4.func1"
   221  		switch intSize {
   222  		case 32:
   223  			return "32"
   224  		case 64:
   225  			return "64"
   226  		default:
   227  			panic("unreachable")
   228  		}
   229  	}() // ERROR "inlining call to switchConst4.func1"
   230  	_ = want
   231  }
   232  
   233  func inlineRangeIntoMe(data []int) { // ERROR "can inline inlineRangeIntoMe" "data does not escape"
   234  	rangeFunc(data, 12) // ERROR "inlining call to rangeFunc"
   235  }
   236  
   237  func rangeFunc(xs []int, b int) int { // ERROR "can inline rangeFunc" "xs does not escape"
   238  	for i, x := range xs {
   239  		if x == b {
   240  			return i
   241  		}
   242  	}
   243  	return -1
   244  }
   245  
   246  type T struct{}
   247  
   248  func (T) meth(int, int) {} // ERROR "can inline T.meth"
   249  
   250  func k() (T, int, int) { return T{}, 0, 0 } // ERROR "can inline k"
   251  
   252  func f3() { // ERROR "can inline f3"
   253  	T.meth(k()) // ERROR "inlining call to k" "inlining call to T.meth"
   254  	// ERRORAUTO "inlining call to T.meth"
   255  }
   256  
   257  func small1() { // ERROR "can inline small1"
   258  	runtime.GC()
   259  }
   260  func small2() int { // ERROR "can inline small2"
   261  	return runtime.GOMAXPROCS(0)
   262  }
   263  func small3(t T) { // ERROR "can inline small3"
   264  	t.meth2(3, 5)
   265  }
   266  func small4(t T) { // not inlineable - has 2 calls.
   267  	t.meth2(runtime.GOMAXPROCS(0), 5)
   268  }
   269  func (T) meth2(int, int) { // not inlineable - has 2 calls.
   270  	runtime.GC()
   271  	runtime.GC()
   272  }
   273  
   274  // Issue #29737 - make sure we can do inlining for a chain of recursive functions
   275  func ee() { // ERROR "can inline ee"
   276  	ff(100) // ERROR "inlining call to ff" "inlining call to gg" "inlining call to hh"
   277  }
   278  
   279  func ff(x int) { // ERROR "can inline ff"
   280  	if x < 0 {
   281  		return
   282  	}
   283  	gg(x - 1) // ERROR "inlining call to gg" "inlining call to hh"
   284  }
   285  func gg(x int) { // ERROR "can inline gg"
   286  	hh(x - 1) // ERROR "inlining call to hh" "inlining call to ff"
   287  }
   288  func hh(x int) { // ERROR "can inline hh"
   289  	ff(x - 1) // ERROR "inlining call to ff" "inlining call to gg"
   290  }
   291  
   292  // Issue #14768 - make sure we can inline for loops.
   293  func for1(fn func() bool) { // ERROR "can inline for1" "fn does not escape"
   294  	for {
   295  		if fn() {
   296  			break
   297  		} else {
   298  			continue
   299  		}
   300  	}
   301  }
   302  
   303  func for2(fn func() bool) { // ERROR "can inline for2" "fn does not escape"
   304  Loop:
   305  	for {
   306  		if fn() {
   307  			break Loop
   308  		} else {
   309  			continue Loop
   310  		}
   311  	}
   312  }
   313  
   314  // Issue #18493 - make sure we can do inlining of functions with a method value
   315  type T1 struct{}
   316  
   317  func (a T1) meth(val int) int { // ERROR "can inline T1.meth"
   318  	return val + 5
   319  }
   320  
   321  func getMeth(t1 T1) func(int) int { // ERROR "can inline getMeth"
   322  	return t1.meth // ERROR "t1.meth escapes to heap"
   323  	// ERRORAUTO "inlining call to T1.meth"
   324  }
   325  
   326  func ii() { // ERROR "can inline ii"
   327  	var t1 T1
   328  	f := getMeth(t1) // ERROR "inlining call to getMeth" "t1.meth does not escape"
   329  	_ = f(3)
   330  }
   331  
   332  // Issue #42194 - make sure that functions evaluated in
   333  // go and defer statements can be inlined.
   334  func gd1(int) {
   335  	defer gd1(gd2()) // ERROR "inlining call to gd2"
   336  	defer gd3()()    // ERROR "inlining call to gd3"
   337  	go gd1(gd2())    // ERROR "inlining call to gd2"
   338  	go gd3()()       // ERROR "inlining call to gd3"
   339  }
   340  
   341  func gd2() int { // ERROR "can inline gd2"
   342  	return 1
   343  }
   344  
   345  func gd3() func() { // ERROR "can inline gd3"
   346  	return ii
   347  }
   348  
   349  // Issue #42788 - ensure ODEREF OCONVNOP* OADDR is low cost.
   350  func EncodeQuad(d []uint32, x [6]float32) { // ERROR "can inline EncodeQuad" "d does not escape"
   351  	_ = d[:6]
   352  	d[0] = float32bits(x[0]) // ERROR "inlining call to float32bits"
   353  	d[1] = float32bits(x[1]) // ERROR "inlining call to float32bits"
   354  	d[2] = float32bits(x[2]) // ERROR "inlining call to float32bits"
   355  	d[3] = float32bits(x[3]) // ERROR "inlining call to float32bits"
   356  	d[4] = float32bits(x[4]) // ERROR "inlining call to float32bits"
   357  	d[5] = float32bits(x[5]) // ERROR "inlining call to float32bits"
   358  }
   359  
   360  // float32bits is a copy of math.Float32bits to ensure that
   361  // these tests pass with `-gcflags=-l`.
   362  func float32bits(f float32) uint32 { // ERROR "can inline float32bits"
   363  	return *(*uint32)(unsafe.Pointer(&f))
   364  }
   365  
   366  // Ensure OCONVNOP is zero cost.
   367  func Conv(v uint64) uint64 { // ERROR "can inline Conv"
   368  	return conv2(conv2(conv2(v))) // ERROR "inlining call to (conv1|conv2)"
   369  }
   370  func conv2(v uint64) uint64 { // ERROR "can inline conv2"
   371  	return conv1(conv1(conv1(conv1(v)))) // ERROR "inlining call to conv1"
   372  }
   373  func conv1(v uint64) uint64 { // ERROR "can inline conv1"
   374  	return uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(v)))))))))))
   375  }
   376  
   377  func select1(x, y chan bool) int { // ERROR "can inline select1" "x does not escape" "y does not escape"
   378  	select {
   379  	case <-x:
   380  		return 1
   381  	case <-y:
   382  		return 2
   383  	}
   384  }
   385  
   386  func select2(x, y chan bool) { // ERROR "can inline select2" "x does not escape" "y does not escape"
   387  loop: // test that labeled select can be inlined.
   388  	select {
   389  	case <-x:
   390  		break loop
   391  	case <-y:
   392  	}
   393  }
   394  
   395  func inlineSelect2(x, y chan bool) { // ERROR "can inline inlineSelect2" ERROR "x does not escape" "y does not escape"
   396  loop:
   397  	for i := 0; i < 5; i++ {
   398  		if i == 3 {
   399  			break loop
   400  		}
   401  		select2(x, y) // ERROR "inlining call to select2"
   402  	}
   403  }
   404  
   405  // Issue #62211: inlining a function with unreachable "return"
   406  // statements could trip up phi insertion.
   407  func issue62211(x bool) { // ERROR "can inline issue62211"
   408  	if issue62211F(x) { // ERROR "inlining call to issue62211F"
   409  	}
   410  	if issue62211G(x) { // ERROR "inlining call to issue62211G"
   411  	}
   412  
   413  	// Initial fix CL caused a "non-monotonic scope positions" failure
   414  	// on code like this.
   415  	if z := 0; false {
   416  		panic(z)
   417  	}
   418  }
   419  
   420  func issue62211F(x bool) bool { // ERROR "can inline issue62211F"
   421  	if x || true {
   422  		return true
   423  	}
   424  	return true
   425  }
   426  
   427  func issue62211G(x bool) bool { // ERROR "can inline issue62211G"
   428  	if x || true {
   429  		return true
   430  	} else {
   431  		return true
   432  	}
   433  }
   434  

View as plain text