diff --git a/src/runtime/panic.go b/src/runtime/panic.go
index 9ae1f982b9..bea2e005ba 100644
--- a/src/runtime/panic.go
+++ b/src/runtime/panic.go
@@ -71,9 +71,9 @@ func panicOrGoexit(message interface{}, panicking panicState) {
 		}
 	}
 	if panicking == panicGoexit {
-		// Call to Goexit() instead of a panic.
+		// This is a call to Goexit() instead of a panic.
 		// Exit the goroutine instead of printing a panic message.
-		deadlock()
+		exitGoroutine()
 	}
 	printstring("panic: ")
 	printitf(message)
diff --git a/src/runtime/scheduler_cooperative.go b/src/runtime/scheduler_cooperative.go
index 3cb1e3f987..f5042b6b31 100644
--- a/src/runtime/scheduler_cooperative.go
+++ b/src/runtime/scheduler_cooperative.go
@@ -45,9 +45,18 @@ var (
 //
 //go:noinline
 func deadlock() {
-	// call yield without requesting a wakeup
+	exitGoroutine()
+}
+
+func exitGoroutine() {
+	// Pause the goroutine without a way for it to wake up.
+	// This makes the goroutine unreachable, and should eventually get it
+	// cleaned up by the GC.
 	task.Pause()
-	panic("unreachable")
+
+	// We will never return from task.Pause(). Make sure the compiler knows
+	// this.
+	trap()
 }
 
 // Add this task to the end of the run queue.
diff --git a/src/runtime/scheduler_none.go b/src/runtime/scheduler_none.go
index dc4b03b6e2..1c2da7eb0a 100644
--- a/src/runtime/scheduler_none.go
+++ b/src/runtime/scheduler_none.go
@@ -36,6 +36,12 @@ func deadlock() {
 	runtimePanic("all goroutines are asleep - deadlock!")
 }
 
+func exitGoroutine() {
+	// There is only one goroutine, which would exit, so that leads to a
+	// deadlock.
+	deadlock()
+}
+
 func scheduleTask(t *task.Task) {
 	// Pause() will panic, so this should not be reachable.
 }