Source file test/inline.go

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

View as plain text