diff --git a/src/cmd/cgo/internal/test/issue42018_windows.go b/src/cmd/cgo/internal/test/issue42018_windows.go
index 8f4570ab2a5915cb3c4a015e5e8007901da6d14c..ea11b8b20b2c8a6e9d44b03eab9d81c12d552ed5 100644
--- a/src/cmd/cgo/internal/test/issue42018_windows.go
+++ b/src/cmd/cgo/internal/test/issue42018_windows.go
@@ -27,6 +27,7 @@ func test42018(t *testing.T) {
 	recurseHWND(400, hwnd, uintptr(unsafe.Pointer(&i)))
 }
 
+//go:noinline
 func recurseHANDLE(n int, p C.HANDLE, v uintptr) {
 	if n > 0 {
 		recurseHANDLE(n-1, p, v)
@@ -36,6 +37,7 @@ func recurseHANDLE(n int, p C.HANDLE, v uintptr) {
 	}
 }
 
+//go:noinline
 func recurseHWND(n int, p C.HWND, v uintptr) {
 	if n > 0 {
 		recurseHWND(n-1, p, v)
diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go
index bddf4aa249c28b14898d5ef6ddd9ba9918a96a91..07db16b280bd26ed7f1b4f19614ce285af2c3a02 100644
--- a/src/cmd/compile/internal/inline/inl.go
+++ b/src/cmd/compile/internal/inline/inl.go
@@ -170,19 +170,8 @@ func CanInlineFuncs(funcs []*ir.Func, profile *pgoir.Profile) {
 	}
 
 	ir.VisitFuncsBottomUp(funcs, func(funcs []*ir.Func, recursive bool) {
-		numfns := numNonClosures(funcs)
-
 		for _, fn := range funcs {
-			if !recursive || numfns > 1 {
-				// We allow inlining if there is no
-				// recursion, or the recursion cycle is
-				// across more than one function.
-				CanInline(fn, profile)
-			} else {
-				if base.Flag.LowerM > 1 && fn.OClosure == nil {
-					fmt.Printf("%v: cannot inline %v: recursive\n", ir.Line(fn), fn.Nname)
-				}
-			}
+			CanInline(fn, profile)
 			if inlheur.Enabled() {
 				analyzeFuncProps(fn, profile)
 			}
@@ -1023,68 +1012,6 @@ func canInlineCallExpr(callerfn *ir.Func, n *ir.CallExpr, callee *ir.Func, bigCa
 		}
 	}
 
-	if callee == callerfn {
-		// Can't recursively inline a function into itself.
-		if log && logopt.Enabled() {
-			logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", fmt.Sprintf("recursive call to %s", ir.FuncName(callerfn)))
-		}
-		return false, 0, false
-	}
-
-	isClosureParent := func(closure, parent *ir.Func) bool {
-		for p := closure.ClosureParent; p != nil; p = p.ClosureParent {
-			if p == parent {
-				return true
-			}
-		}
-		return false
-	}
-	if isClosureParent(callerfn, callee) {
-		// Can't recursively inline a parent of the closure into itself.
-		if log && logopt.Enabled() {
-			logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", fmt.Sprintf("recursive call to closure parent: %s, %s", ir.FuncName(callerfn), ir.FuncName(callee)))
-		}
-		return false, 0, false
-	}
-	if isClosureParent(callee, callerfn) {
-		// Can't recursively inline a closure if there's a call to the parent in closure body.
-		if ir.Any(callee, func(node ir.Node) bool {
-			if call, ok := node.(*ir.CallExpr); ok {
-				if name, ok := call.Fun.(*ir.Name); ok && isClosureParent(callerfn, name.Func) {
-					return true
-				}
-			}
-			return false
-		}) {
-			if log && logopt.Enabled() {
-				logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", fmt.Sprintf("recursive call to closure parent: %s, %s", ir.FuncName(callerfn), ir.FuncName(callee)))
-			}
-			return false, 0, false
-		}
-	}
-	do := func(fn *ir.Func) bool {
-		// Can't recursively inline a function if the function body contains
-		// a call to a function f, which the function f is one of the call arguments.
-		return ir.Any(fn, func(node ir.Node) bool {
-			if call, ok := node.(*ir.CallExpr); ok {
-				for _, arg := range call.Args {
-					if call.Fun == arg {
-						return true
-					}
-				}
-			}
-			return false
-		})
-	}
-	for _, fn := range []*ir.Func{callerfn, callee} {
-		if do(fn) {
-			if log && logopt.Enabled() {
-				logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", fmt.Sprintf("recursive call to function: %s", ir.FuncName(fn)))
-			}
-			return false, 0, false
-		}
-	}
-
 	if base.Flag.Cfg.Instrumenting && types.IsNoInstrumentPkg(callee.Sym().Pkg) {
 		// Runtime package must not be instrumented.
 		// Instrument skips runtime package. However, some runtime code can be
diff --git a/src/runtime/pprof/proto_test.go b/src/runtime/pprof/proto_test.go
index caaaa45f1257ebd666fa7c08cf3d7ad0c1b1aeab..a4ae95d4c4d95c1fcabfe4f6266fb1f32496b984 100644
--- a/src/runtime/pprof/proto_test.go
+++ b/src/runtime/pprof/proto_test.go
@@ -73,7 +73,10 @@ func TestConvertCPUProfileNoSamples(t *testing.T) {
 	checkProfile(t, p, 2000*1000, periodType, sampleType, nil, "")
 }
 
+//go:noinline
 func f1() { f1() }
+
+//go:noinline
 func f2() { f2() }
 
 // testPCs returns two PCs and two corresponding memory mappings
diff --git a/test/fixedbugs/issue40954.go b/test/fixedbugs/issue40954.go
index 0beaabb7439755853d0f4d247e423b3b40bf11a1..8b303b12e65a2cc59f548ebb0a3ffaefe0b6f131 100644
--- a/test/fixedbugs/issue40954.go
+++ b/test/fixedbugs/issue40954.go
@@ -30,6 +30,8 @@ func main() {
 	// should not be adjusted when the stack is copied.
 	recurse(100, p, v)
 }
+
+//go:noinline
 func recurse(n int, p *S, v uintptr) {
 	if n > 0 {
 		recurse(n-1, p, v)
diff --git a/test/fixedbugs/issue52193.go b/test/fixedbugs/issue52193.go
index 1c42210f080570e28ccca7113cef3fb50581d281..c7afc9312f55760e16943cc886eb11f3a93fa769 100644
--- a/test/fixedbugs/issue52193.go
+++ b/test/fixedbugs/issue52193.go
@@ -11,14 +11,14 @@ package p
 
 func f() { // ERROR "can inline f"
 	var i interface{ m() } = T(0) // ERROR "T\(0\) does not escape"
-	i.m()                         // ERROR "devirtualizing i.m" "inlining call to T.m"
+	i.m()                         // ERROR "devirtualizing i.m" "inlining call to T.m" "inlining call to f" "T\(0\) does not escape"
 }
 
 type T int
 
 func (T) m() { // ERROR "can inline T.m"
 	if never {
-		f() // ERROR "inlining call to f" "devirtualizing i.m" "T\(0\) does not escape"
+		f() // ERROR "inlining call to f" "devirtualizing i.m" "T\(0\) does not escape" "inlining call to T.m"
 	}
 }
 
diff --git a/test/fixedbugs/issue54159.go b/test/fixedbugs/issue54159.go
index 0f607b38e12020bef668b5c0f0d896c88a2e5a3a..8a29bc5cbaab5e83e74e6481d579e6070697930f 100644
--- a/test/fixedbugs/issue54159.go
+++ b/test/fixedbugs/issue54159.go
@@ -6,7 +6,8 @@
 
 package main
 
-func run() { // ERROR "cannot inline run: recursive"
+//go:noinline
+func run() { // ERROR "cannot inline run: marked go:noinline"
 	f := func() { // ERROR "can inline run.func1 with cost .* as:.*" "func literal does not escape"
 		g() // ERROR "inlining call to g"
 	}
diff --git a/test/inline.go b/test/inline.go
index 4714c795c2fdbaa787eb2a8e23142576299979c6..3ed4b1de451ff1fc144e2cab3f7c18c007f26609 100644
--- a/test/inline.go
+++ b/test/inline.go
@@ -280,13 +280,13 @@ func ff(x int) { // ERROR "can inline ff"
 	if x < 0 {
 		return
 	}
-	gg(x - 1) // ERROR "inlining call to gg" "inlining call to hh"
+	gg(x - 1) // ERROR "inlining call to gg" "inlining call to hh" "inlining call to ff"
 }
 func gg(x int) { // ERROR "can inline gg"
-	hh(x - 1) // ERROR "inlining call to hh" "inlining call to ff"
+	hh(x - 1) // ERROR "inlining call to hh" "inlining call to ff" "inlining call to gg"
 }
 func hh(x int) { // ERROR "can inline hh"
-	ff(x - 1) // ERROR "inlining call to ff" "inlining call to gg"
+	ff(x - 1) // ERROR "inlining call to ff" "inlining call to gg" "inlining call to hh"
 }
 
 // Issue #14768 - make sure we can inline for loops.
@@ -332,9 +332,9 @@ func ii() { // ERROR "can inline ii"
 // 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 gd1(gd2()) // ERROR "inlining call to gd2" "can inline gd1.deferwrap1"
 	defer gd3()()    // ERROR "inlining call to gd3"
-	go gd1(gd2())    // ERROR "inlining call to gd2"
+	go gd1(gd2())    // ERROR "inlining call to gd2" "can inline gd1.gowrap2"
 	go gd3()()       // ERROR "inlining call to gd3"
 }
 
diff --git a/test/loopbce.go b/test/loopbce.go
index 2d5c965ae700bb7faed4aac9ab8c308f3917501e..8bc44ece9455a0c87c41ada47fe8119f7234bc93 100644
--- a/test/loopbce.go
+++ b/test/loopbce.go
@@ -88,6 +88,7 @@ func f5_int8(a [10]int) int {
 	return x
 }
 
+//go:noinline
 func f6(a []int) {
 	for i := range a { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
 		b := a[0:i] // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$"
diff --git a/test/newinline.go b/test/newinline.go
index a7288691cd24fa816bcded335e7b5f9bf25d02fc..da299d5543e64b7eda8f70bb83aa3df6650ff8cb 100644
--- a/test/newinline.go
+++ b/test/newinline.go
@@ -280,13 +280,13 @@ func ff(x int) { // ERROR "can inline ff"
 	if x < 0 {
 		return
 	}
-	gg(x - 1) // ERROR "inlining call to gg" "inlining call to hh"
+	gg(x - 1) // ERROR "inlining call to gg" "inlining call to hh" "inlining call to ff"
 }
 func gg(x int) { // ERROR "can inline gg"
-	hh(x - 1) // ERROR "inlining call to hh" "inlining call to ff"
+	hh(x - 1) // ERROR "inlining call to hh" "inlining call to ff" "inlining call to gg"
 }
 func hh(x int) { // ERROR "can inline hh"
-	ff(x - 1) // ERROR "inlining call to ff" "inlining call to gg"
+	ff(x - 1) // ERROR "inlining call to ff" "inlining call to gg" "inlining call to hh"
 }
 
 // Issue #14768 - make sure we can inline for loops.