Source file test/inline.go

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

View as plain text