summaryrefslogtreecommitdiffstats
path: root/test/inline.go
diff options
context:
space:
mode:
Diffstat (limited to 'test/inline.go')
-rw-r--r--test/inline.go305
1 files changed, 305 insertions, 0 deletions
diff --git a/test/inline.go b/test/inline.go
new file mode 100644
index 0000000..2780e10
--- /dev/null
+++ b/test/inline.go
@@ -0,0 +1,305 @@
+// errorcheckwithauto -0 -m -d=inlfuncswithclosures=1
+
+// Copyright 2015 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.
+
+// Test, using compiler diagnostic flags, that inlining is working.
+// Compiles but does not run.
+
+package foo
+
+import (
+ "runtime"
+ "unsafe"
+)
+
+func add2(p *byte, n uintptr) *byte { // ERROR "can inline add2" "leaking param: p to result"
+ return (*byte)(add1(unsafe.Pointer(p), n)) // ERROR "inlining call to add1"
+}
+
+func add1(p unsafe.Pointer, x uintptr) unsafe.Pointer { // ERROR "can inline add1" "leaking param: p to result"
+ return unsafe.Pointer(uintptr(p) + x)
+}
+
+func f(x *byte) *byte { // ERROR "can inline f" "leaking param: x to result"
+ return add2(x, 1) // ERROR "inlining call to add2" "inlining call to add1"
+}
+
+//go:noinline
+func g(x int) int {
+ return x + 1
+}
+
+func h(x int) int { // ERROR "can inline h"
+ return x + 2
+}
+
+func i(x int) int { // ERROR "can inline i"
+ const y = 2
+ return x + y
+}
+
+func j(x int) int { // ERROR "can inline j"
+ switch {
+ case x > 0:
+ return x + 2
+ default:
+ return x + 1
+ }
+}
+
+func f2() int { // ERROR "can inline f2"
+ tmp1 := h
+ tmp2 := tmp1
+ return tmp2(0) // ERROR "inlining call to h"
+}
+
+var somethingWrong error
+
+// local closures can be inlined
+func l(x, y int) (int, int, error) { // ERROR "can inline l"
+ e := func(err error) (int, int, error) { // ERROR "can inline l.func1" "func literal does not escape" "leaking param: err to result"
+ return 0, 0, err
+ }
+ if x == y {
+ e(somethingWrong) // ERROR "inlining call to l.func1"
+ } else {
+ f := e
+ f(nil) // ERROR "inlining call to l.func1"
+ }
+ return y, x, nil
+}
+
+// any re-assignment prevents closure inlining
+func m() int {
+ foo := func() int { return 1 } // ERROR "can inline m.func1" "func literal does not escape"
+ x := foo()
+ foo = func() int { return 2 } // ERROR "can inline m.func2" "func literal does not escape"
+ return x + foo()
+}
+
+// address taking prevents closure inlining
+func n() int {
+ foo := func() int { return 1 } // ERROR "can inline n.func1" "func literal does not escape"
+ bar := &foo
+ x := (*bar)() + foo()
+ return x
+}
+
+// make sure assignment inside closure is detected
+func o() int {
+ foo := func() int { return 1 } // ERROR "can inline o.func1" "func literal does not escape"
+ func(x int) { // ERROR "can inline o.func2"
+ if x > 10 {
+ foo = func() int { return 2 } // ERROR "can inline o.func2"
+ }
+ }(11) // ERROR "func literal does not escape" "inlining call to o.func2"
+ return foo()
+}
+
+func p() int { // ERROR "can inline p"
+ return func() int { return 42 }() // ERROR "can inline p.func1" "inlining call to p.func1"
+}
+
+func q(x int) int { // ERROR "can inline q"
+ foo := func() int { return x * 2 } // ERROR "can inline q.func1" "func literal does not escape"
+ return foo() // ERROR "inlining call to q.func1"
+}
+
+func r(z int) int {
+ foo := func(x int) int { // ERROR "can inline r.func1" "func literal does not escape"
+ return x + z
+ }
+ bar := func(x int) int { // ERROR "func literal does not escape" "can inline r.func2"
+ return x + func(y int) int { // ERROR "can inline r.func2.1" "can inline r.func3"
+ return 2*y + x*z
+ }(x) // ERROR "inlining call to r.func2.1"
+ }
+ return foo(42) + bar(42) // ERROR "inlining call to r.func1" "inlining call to r.func2" "inlining call to r.func3"
+}
+
+func s0(x int) int { // ERROR "can inline s0"
+ foo := func() { // ERROR "can inline s0.func1" "func literal does not escape"
+ x = x + 1
+ }
+ foo() // ERROR "inlining call to s0.func1"
+ return x
+}
+
+func s1(x int) int { // ERROR "can inline s1"
+ foo := func() int { // ERROR "can inline s1.func1" "func literal does not escape"
+ return x
+ }
+ x = x + 1
+ return foo() // ERROR "inlining call to s1.func1"
+}
+
+func switchBreak(x, y int) int { // ERROR "can inline switchBreak"
+ var n int
+ switch x {
+ case 0:
+ n = 1
+ Done:
+ switch y {
+ case 0:
+ n += 10
+ break Done
+ }
+ n = 2
+ }
+ return n
+}
+
+func switchType(x interface{}) int { // ERROR "can inline switchType" "x does not escape"
+ switch x.(type) {
+ case int:
+ return x.(int)
+ default:
+ return 0
+ }
+}
+
+func inlineRangeIntoMe(data []int) { // ERROR "can inline inlineRangeIntoMe" "data does not escape"
+ rangeFunc(data, 12) // ERROR "inlining call to rangeFunc"
+}
+
+func rangeFunc(xs []int, b int) int { // ERROR "can inline rangeFunc" "xs does not escape"
+ for i, x := range xs {
+ if x == b {
+ return i
+ }
+ }
+ return -1
+}
+
+type T struct{}
+
+func (T) meth(int, int) {} // ERROR "can inline T.meth"
+
+func k() (T, int, int) { return T{}, 0, 0 } // ERROR "can inline k"
+
+func f3() { // ERROR "can inline f3"
+ T.meth(k()) // ERROR "inlining call to k" "inlining call to T.meth"
+ // ERRORAUTO "inlining call to T.meth"
+}
+
+func small1() { // ERROR "can inline small1"
+ runtime.GC()
+}
+func small2() int { // ERROR "can inline small2"
+ return runtime.GOMAXPROCS(0)
+}
+func small3(t T) { // ERROR "can inline small3"
+ t.meth2(3, 5)
+}
+func small4(t T) { // not inlineable - has 2 calls.
+ t.meth2(runtime.GOMAXPROCS(0), 5)
+}
+func (T) meth2(int, int) { // not inlineable - has 2 calls.
+ runtime.GC()
+ runtime.GC()
+}
+
+// Issue #29737 - make sure we can do inlining for a chain of recursive functions
+func ee() { // ERROR "can inline ee"
+ ff(100) // ERROR "inlining call to ff" "inlining call to gg" "inlining call to hh"
+}
+
+func ff(x int) { // ERROR "can inline ff"
+ if x < 0 {
+ return
+ }
+ gg(x - 1)
+}
+func gg(x int) { // ERROR "can inline gg"
+ hh(x - 1)
+}
+func hh(x int) { // ERROR "can inline hh"
+ ff(x - 1) // ERROR "inlining call to ff" // ERROR "inlining call to gg"
+}
+
+// Issue #14768 - make sure we can inline for loops.
+func for1(fn func() bool) { // ERROR "can inline for1" "fn does not escape"
+ for {
+ if fn() {
+ break
+ } else {
+ continue
+ }
+ }
+}
+
+func for2(fn func() bool) { // ERROR "can inline for2" "fn does not escape"
+Loop:
+ for {
+ if fn() {
+ break Loop
+ } else {
+ continue Loop
+ }
+ }
+}
+
+// Issue #18493 - make sure we can do inlining of functions with a method value
+type T1 struct{}
+
+func (a T1) meth(val int) int { // ERROR "can inline T1.meth"
+ return val + 5
+}
+
+func getMeth(t1 T1) func(int) int { // ERROR "can inline getMeth"
+ return t1.meth // ERROR "t1.meth escapes to heap"
+ // ERRORAUTO "inlining call to T1.meth"
+}
+
+func ii() { // ERROR "can inline ii"
+ var t1 T1
+ f := getMeth(t1) // ERROR "inlining call to getMeth" "t1.meth does not escape"
+ _ = f(3)
+}
+
+// Issue #42194 - make sure that functions evaluated in
+// go and defer statements can be inlined.
+func gd1(int) {
+ defer gd1(gd2()) // ERROR "inlining call to gd2"
+ defer gd3()() // ERROR "inlining call to gd3"
+ go gd1(gd2()) // ERROR "inlining call to gd2"
+ go gd3()() // ERROR "inlining call to gd3"
+}
+
+func gd2() int { // ERROR "can inline gd2"
+ return 1
+}
+
+func gd3() func() { // ERROR "can inline gd3"
+ return ii
+}
+
+// Issue #42788 - ensure ODEREF OCONVNOP* OADDR is low cost.
+func EncodeQuad(d []uint32, x [6]float32) { // ERROR "can inline EncodeQuad" "d does not escape"
+ _ = d[:6]
+ d[0] = float32bits(x[0]) // ERROR "inlining call to float32bits"
+ d[1] = float32bits(x[1]) // ERROR "inlining call to float32bits"
+ d[2] = float32bits(x[2]) // ERROR "inlining call to float32bits"
+ d[3] = float32bits(x[3]) // ERROR "inlining call to float32bits"
+ d[4] = float32bits(x[4]) // ERROR "inlining call to float32bits"
+ d[5] = float32bits(x[5]) // ERROR "inlining call to float32bits"
+}
+
+// float32bits is a copy of math.Float32bits to ensure that
+// these tests pass with `-gcflags=-l`.
+func float32bits(f float32) uint32 { // ERROR "can inline float32bits"
+ return *(*uint32)(unsafe.Pointer(&f))
+}
+
+// Ensure OCONVNOP is zero cost.
+func Conv(v uint64) uint64 { // ERROR "can inline Conv"
+ return conv2(conv2(conv2(v))) // ERROR "inlining call to (conv1|conv2)"
+}
+func conv2(v uint64) uint64 { // ERROR "can inline conv2"
+ return conv1(conv1(conv1(conv1(v)))) // ERROR "inlining call to conv1"
+}
+func conv1(v uint64) uint64 { // ERROR "can inline conv1"
+ return uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(v)))))))))))
+}