2015-02-24 10:19:01 -07:00
// errorcheck -0 -m
2016-04-10 15:32:26 -06:00
// Copyright 2015 The Go Authors. All rights reserved.
2015-02-24 10:19:01 -07:00
// 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
2017-09-18 15:54:10 -06:00
import (
"errors"
2018-11-04 20:23:08 -07:00
"runtime"
2017-09-18 15:54:10 -06:00
"unsafe"
)
2015-02-24 10:19:01 -07:00
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"
}
2015-08-24 18:45:59 -06:00
//go:noinline
func g ( x int ) int {
return x + 1
}
func h ( x int ) int { // ERROR "can inline h"
return x + 2
}
2016-03-16 17:44:17 -06:00
func i ( x int ) int { // ERROR "can inline i"
const y = 2
return x + y
}
2016-03-16 20:29:17 -06:00
func j ( x int ) int { // ERROR "can inline j"
switch {
case x > 0 :
return x + 2
default :
return x + 1
}
}
2020-09-14 13:56:37 -06:00
var somethingWrong error = errors . New ( "something went wrong" ) // ERROR "can inline init" "inlining call to errors.New" "errors.errorString.* escapes to heap"
2017-09-18 15:54:10 -06:00
// local closures can be inlined
func l ( x , y int ) ( int , int , error ) {
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"
}
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"
2019-04-01 12:58:33 -06:00
bar := & foo
2017-09-18 15:54:10 -06:00
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 "func literal does not escape"
if x > 10 {
foo = func ( ) int { return 2 } // ERROR "can inline o.func2" "func literal escapes"
}
} ( 11 )
return foo ( )
}
func p ( ) int {
return func ( ) int { return 42 } ( ) // ERROR "can inline p.func1" "inlining call to p.func1"
}
2017-10-21 16:58:37 -06:00
func q ( x int ) int {
2019-09-12 11:18:03 -06:00
foo := func ( ) int { return x * 2 } // ERROR "can inline q.func1" "func literal does not escape"
2017-10-21 16:58:37 -06:00
return foo ( ) // ERROR "inlining call to q.func1"
}
func r ( z int ) int {
2019-09-12 11:18:03 -06:00
foo := func ( x int ) int { // ERROR "can inline r.func1" "func literal does not escape"
2017-10-21 16:58:37 -06:00
return x + z
}
2019-09-12 11:18:03 -06:00
bar := func ( x int ) int { // ERROR "func literal does not escape"
2017-10-21 16:58:37 -06:00
return x + func ( y int ) int { // ERROR "can inline r.func2.1"
return 2 * y + x * z
} ( x ) // ERROR "inlining call to r.func2.1"
}
return foo ( 42 ) + bar ( 42 ) // ERROR "inlining call to r.func1"
}
func s0 ( x int ) int {
2019-09-12 11:18:03 -06:00
foo := func ( ) { // ERROR "can inline s0.func1" "func literal does not escape"
2017-10-21 16:58:37 -06:00
x = x + 1
}
2019-04-01 12:58:33 -06:00
foo ( ) // ERROR "inlining call to s0.func1"
2017-10-21 16:58:37 -06:00
return x
}
func s1 ( x int ) int {
2019-09-12 11:18:03 -06:00
foo := func ( ) int { // ERROR "can inline s1.func1" "func literal does not escape"
2017-10-21 16:58:37 -06:00
return x
}
x = x + 1
2019-04-01 12:58:33 -06:00
return foo ( ) // ERROR "inlining call to s1.func1"
2017-10-21 16:58:37 -06:00
}
2016-03-16 20:29:17 -06:00
// can't currently inline functions with a break statement
func switchBreak ( x , y int ) int {
var n int
switch x {
case 0 :
n = 1
Done :
switch y {
case 0 :
n += 10
break Done
}
n = 2
}
return n
}
// can't currently inline functions with a type switch
2019-09-12 11:18:03 -06:00
func switchType ( x interface { } ) int { // ERROR "x does not escape"
2016-03-16 20:29:17 -06:00
switch x . ( type ) {
case int :
return x . ( int )
default :
return 0
}
}
2017-10-10 10:35:11 -06:00
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 _ ( ) { // ERROR "can inline _"
T . meth ( k ( ) ) // ERROR "inlining call to k" "inlining call to T.meth"
}
2018-11-04 20:23:08 -07:00
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 ( )
}
2020-03-31 21:24:05 -06:00
// 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"
}