Go version

go1.24.4

Output of go env in your module/workspace:

AR='ar'
CC='gcc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='g++'
GCCGO='gccgo'
GO111MODULE=''
GOAMD64='v1'
GOARCH='amd64'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/home/apocalypse555/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/home/apocalypse555/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build1252593989=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/dev/null'
GOMODCACHE='/home/apocalypse555/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/apocalypse555/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/lib/go'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/apocalypse555/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/lib/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.24.4'
GOWORK=''
PKG_CONFIG='pkg-config'

What did you do?

I run go vet on this code :

func ok(a int) bool {
    if a < 10 {
        //panic(`with that, it's well detected`)
        os.Exit(1)
        return false
    }
    return true
}

(https://go.dev/play/p/CHtVr0fs-yw)

What did you see happen?

No warning like with panic().

What did you expect to see?

A warning like with panic().

It seems odd that an unreachable code is detected after a panic() but not after an os.Exit().

Related issue

https://github.com/golang/go/issues/53968

Comment From: randall77

Adding return false is required in many cases to adhere to the language spec on terminating statements.

func f(b bool) int {
    if b {
        return 5
    } else {
        os.Exit(1)
        return 0 // doesn't compile without this line
    }
}

The language spec doesn't say that os.Exit is a terminating statement. I'm not sure it should, as the spec doesn't mention specific packages very often. And changing the definition of terminating statement now would break existing programs.

I suppose vet could find code like the code in your case, where removing it doesn't invalidate the program. That's an extra complication, and I'm not sure how often such a constrained vet rule would trigger.

Comment From: cagedmantis

@adonovan @matloob

Comment From: adonovan

I did an experiment a long time ago to make cmd/vet smarter about dead code following calls to "no-return" functions. The ctrlflow analyzer already knows about such functions, so basing unreachable atop ctrflow would do most of the heavy lifting. I just shared some old prototype code in https://go.dev/cl/687635, but it needs some care to make it production-worthy.

I think the ideal behavior would be for the analyzer to offer a fix to turn any statement following a noreturn call into panic("unreachable").

Comment From: gopherbot

Change https://go.dev/cl/687635 mentions this issue: go/analysis/passes/unreachable: use ctrlflow analyzer

Comment From: TapirLiu

And runtime.Goexit. I'm surprised that it is not mentioned in Go spec at all. And its doc also doesn't mention the fact that if can cancel panics.

package main

import "runtime"

func main() {
    var c = make(chan int)
    go func() {
        defer func() {
            c <- 1
        }()
        defer func() {
            runtime.Goexit() // cancel panic "bye"
        }()
        panic("bye")
    }()
    <-c
}

Comment From: seankhliao

seems like there's not a lot of code that has this problem, is this frequent enough for vet? https://github.com/search?q=language%3AGo+%2F%5E%5Cs%2Bos.Exit%5C%28.*%5C%29%5Cn%5Cs%2B%5Bae-os-z%5D%2F&type=code

regex is sort of limited, so search excludes: - [b]reak - [c]ase - [d]efault - [p]anic - [r]eturn - }

Comment From: adonovan

Here's the result of applying https://go.dev/cl/687635 to the Module Mirror corpus. It reported 7241 diagnostics in 24K modules (though many of those had build errors):

unreachable.txt

A quick inspection of ten at random shows that 7 are valid and 3 are signs of serious bugs in the analyzer: - https://go-mod-viewer.appspot.com/github.com/cznic/cc@v0.0.0-20181122101902-d673e9b70d4d/v2/ast2.go#L3771 - https://go-mod-viewer.appspot.com/github.com/Kucoin/kucoin-go-sdk@v1.2.18/order_test.go#L176 - https://go-mod-viewer.appspot.com/github.com/Augustu/go-micro/v2@v2.9.3/debug/log/kubernetes/kubernetes_test.go#L54

I guess I have more work to do here.

A random 50 are shown below.

https://go-mod-viewer.appspot.com/github.com/cloudwan/edgelq-sdk@v1.15.4/audit/resources/v1alpha2/common/common.pb.fieldpath.go#L2983: unreachable code https://go-mod-viewer.appspot.com/github.com/Kucoin/kucoin-go-sdk@v1.2.18/order_test.go#L176: unreachable code https://go-mod-viewer.appspot.com/github.com/cloudwan/edgelq-sdk@v1.15.4/alerting/resources/v1/common/specs.pb.fieldpath.go#L15077: unreachable code https://go-mod-viewer.appspot.com/github.com/ethereum/go-ethereum@v1.16.1/internal/cmdtest/test_cmd.go#L170: unreachable code https://go-mod-viewer.appspot.com/github.com/pachyderm/pachyderm@v1.13.4/src/server/admin/server/convert1_10.go#L488: unreachable code https://go-mod-viewer.appspot.com/github.com/epsagon/epsagon-go@v1.39.0/example/s3_example/write/main.go#L58: unreachable code https://go-mod-viewer.appspot.com/github.com/snikch/goodman@v0.0.0-20171125024755-10e37e294daa/example/main.go#L23: unreachable code https://go-mod-viewer.appspot.com/github.com/cloudwan/edgelq-sdk@v1.15.4/logging/client/v1alpha2/log_descriptor/log_descriptor_service.pb.descriptors.go#L1351: unreachable code https://go-mod-viewer.appspot.com/github.com/cznic/cc@v0.0.0-20181122101902-d673e9b70d4d/v2/ast2.go#L3771: unreachable code https://go-mod-viewer.appspot.com/github.com/Augustu/go-micro/v2@v2.9.3/debug/log/kubernetes/kubernetes_test.go#L54: unreachable code https://go-mod-viewer.appspot.com/github.com/whiteCcinn/protobuf-go@v1.0.9/internal/testprotos/legacy/proto2_20160225_2fc053c5/test.pb.go#L1826: unreachable code https://go-mod-viewer.appspot.com/github.com/CESSProject/cess-go-sdk@v0.7.2/example/chain/parseblock/parseblock.go#L120: unreachable code https://go-mod-viewer.appspot.com/github.com/aws/aws-encryption-sdk/releases/go/encryption-sdk@v0.2.0/KeyDerivation/KeyDerivation.go#L448: unreachable code https://go-mod-viewer.appspot.com/sourcegraph.com/sourcegraph/go-vcs@v0.0.0-20230717073621-ca41431d1b7d/vcs/git/repo.go#L296: unreachable code https://go-mod-viewer.appspot.com/github.com/cloudwan/edgelq-sdk@v1.15.4/monitoring/resources/v4/alert/alert.pb.fieldpath.go#L3327: unreachable code https://go-mod-viewer.appspot.com/github.com/conbanwa/logs@v0.4.7/compare.go#L176: unreachable code https://go-mod-viewer.appspot.com/github.com/aws/aws-cryptographic-material-providers-library/releases/go/smithy-dafny-standard-library@v0.2.0/Actions/Actions.go#L191: unreachable code https://go-mod-viewer.appspot.com/github.com/Venafi/vcert/v5@v5.10.2/pkg/venafi/tpp/connector_test.go#L577: unreachable code https://go-mod-viewer.appspot.com/github.com/Kucoin/kucoin-go-sdk@v1.2.18/margin_test.go#L294: unreachable code https://go-mod-viewer.appspot.com/github.com/charlesetsmith/saratoga/sarflags@v0.0.0-20240223233549-4e862e6c4217/sarflags.go#L807: unreachable code https://go-mod-viewer.appspot.com/github.com/cockroachdb/pebble@v1.1.5/scan_internal_test.go#L337: unreachable code https://go-mod-viewer.appspot.com/github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl@v0.2.0/IntermediateKeyWrapping/IntermediateKeyWrapping.go#L526: unreachable code https://go-mod-viewer.appspot.com/github.com/cloudwan/edgelq-sdk@v1.15.4/applications/resources/v1alpha2/pod/pod.pb.fieldpath.go#L3007: unreachable code https://go-mod-viewer.appspot.com/github.com/vishvananda/netlink@v1.3.1/filter_test.go#L1146: unreachable code https://go-mod-viewer.appspot.com/github.com/decred/dcrlnd@v0.7.6/cmd/dcrlncli/cmd_open_channel.go#L587: unreachable code https://go-mod-viewer.appspot.com/github.com/balzaczyy/golucene@v0.0.0-20151210033525-d0be9ee89713/core/index/writer.go#L1399: unreachable code https://go-mod-viewer.appspot.com/github.com/core-coin/go-core@v1.1.7/p2p/discover/ntp_test.go#L25: unreachable code https://go-mod-viewer.appspot.com/github.com/network-quality/goresponsiveness@v0.0.0-20240129151524-343954285090/probe/tracer.go#L113: unreachable code https://go-mod-viewer.appspot.com/github.com/core-coin/go-core@v1.1.7/p2p/discover/ntp_test.go#L31: unreachable code https://go-mod-viewer.appspot.com/github.com/theQRL/go-zond@v0.2.1/trie/stacktrie_test.go#L329: unreachable code https://go-mod-viewer.appspot.com/github.com/TIBCOSoftware/flogo-lib@v0.5.9/core/mapper/exprmapper/expression/expression_test.go#L263: unreachable code https://go-mod-viewer.appspot.com/github.com/xujiajun/gorouter@v1.2.0/router_test.go#L219: unreachable code https://go-mod-viewer.appspot.com/github.com/epsagon/epsagon-go@v1.39.0/example/sts_example/main.go#L41: unreachable code https://go-mod-viewer.appspot.com/github.com/luckypickle/go-ethereum-vet@v1.14.2/signer/rules/rules_test.go#L521: unreachable code https://go-mod-viewer.appspot.com/github.com/cznic/fileutil@v0.0.0-20181122101858-4d67cfea8c87/storage/probe_test.go#L44: unreachable code https://go-mod-viewer.appspot.com/github.com/symfony-cli/console@v1.2.1/flag_test.go#L1229: unreachable code https://go-mod-viewer.appspot.com/github.com/whiteCcinn/protobuf-go@v1.0.9/internal/testprotos/legacy/proto3_20160225_2fc053c5/test.pb.go#L758: unreachable code https://go-mod-viewer.appspot.com/github.com/btnguyen2k/consu/semita@v0.1.5/Semita_test.go#L2543: unreachable code https://go-mod-viewer.appspot.com/github.com/uber-go/tally/v4@v4.1.17/thirdparty/github.com/apache/thrift/lib/go/thrift/protocol_test.go#L109: unreachable code https://go-mod-viewer.appspot.com/github.com/cohesity/app-sdk-go@v0.0.0-20190722230114-5dbb9337cc19/unirest-go/Request.go#L131: unreachable code https://go-mod-viewer.appspot.com/github.com/nicocha30/gvisor-ligolo@v0.0.0-20250509122847-3be646365354/pkg/abi/linux/linux_abi_autogen_unsafe.go#L5436: unreachable code https://go-mod-viewer.appspot.com/github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/service/debug/log/kubernetes/kubernetes_test.go#L44: unreachable code https://go-mod-viewer.appspot.com/modernc.org/cc@v1.0.1/v2/ast2.go#L3894: unreachable code https://go-mod-viewer.appspot.com/github.com/gogf/gf@v1.16.9/database/gdb/gdb_z_mysql_transaction_test.go#L1069: unreachable code https://go-mod-viewer.appspot.com/github.com/btnguyen2k/consu/semita@v0.1.5/Semita_test.go#L2087: unreachable code https://go-mod-viewer.appspot.com/github.com/cloudwan/edgelq-sdk@v1.15.4/monitoring/client/v4/project/project_service.pb.descriptors.go#L1448: unreachable code https://go-mod-viewer.appspot.com/github.com/terraform-linters/tflint-plugin-sdk@v0.22.0/plugin/internal/plugin2host/plugin2host_test.go#L749: unreachable code https://go-mod-viewer.appspot.com/github.com/glycerine/goconvey@v0.0.0-20190410193231-58a59202ab31/convey/assertions/ignorespaces.go#L330: unreachable code https://go-mod-viewer.appspot.com/github.com/cloudwan/edgelq-sdk@v1.15.4/devices/resources/v1/device/device.pb.fieldpath.go#L18980: unreachable code https://go-mod-viewer.appspot.com/github.com/hashicorp/terraform-plugin-sdk@v1.17.2/terraform/upgrade_state_v1_test.go#L68: unreachable code ecosystem$