Go version
go version go1.27-devel_24ec7d2120 Fri May 22 20:16:59 2026 -0700 linux/amd64
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/yukatan/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/home/yukatan/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build1451256312=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/dev/null'
GOMODCACHE='/home/yukatan/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPACKAGESDRIVER=''
GOPATH='/home/yukatan/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/home/yukatan/gerrit/go'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/yukatan/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/home/yukatan/gerrit/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.27-devel_24ec7d2120 Fri May 22 20:16:59 2026 -0700'
GOWORK=''
PKG_CONFIG='pkg-config'
What did you do?
Consider the following example:
// main.go
package main
func main() {
const N = 10000
a := make([]int, 0)
for i := 0; i < N; i++ {
a = append(a, i)
}
}
I compiled this one with the GOEXPERIMENT=runtimefreegc enabled:
$ GOEXPERIMENT=runtimefreegc go build -gcflags='-S' -o /dev/null ./main.go
What did you see happen?
Nothing happened, no calls to runtime.growsliceNoAlias were generated:
main.main STEXT size=174 align=0x0 args=0x0 locals=0x78 funcid=0x0
0x0000 00000 (/home/yukatan/freegc/main.go:5) TEXT main.main(SB), ABIInternal, $120-0
0x0000 00000 (/home/yukatan/freegc/main.go:5) CMPQ SP, 16(R14)
0x0004 00004 (/home/yukatan/freegc/main.go:5) PCDATA $0, $-2
0x0004 00004 (/home/yukatan/freegc/main.go:5) JLS 164
0x000a 00010 (/home/yukatan/freegc/main.go:5) PCDATA $0, $-1
0x000a 00010 (/home/yukatan/freegc/main.go:5) PUSHQ BP
0x000b 00011 (/home/yukatan/freegc/main.go:5) MOVQ SP, BP
0x000e 00014 (/home/yukatan/freegc/main.go:5) SUBQ $112, SP
0x0012 00018 (/home/yukatan/freegc/main.go:5) FUNCDATA $0, gclocals·g5+hNtRBP6YXNjfog7aZjQ==(SB)
0x0012 00018 (/home/yukatan/freegc/main.go:5) FUNCDATA $1, gclocals·g5+hNtRBP6YXNjfog7aZjQ==(SB)
0x0012 00018 (/home/yukatan/freegc/main.go:8) XORL DX, DX
0x0014 00020 (/home/yukatan/freegc/main.go:8) LEAQ main..autotmp_2+112(SP), R8
0x0019 00025 (/home/yukatan/freegc/main.go:8) XORL R9, R9
0x001c 00028 (/home/yukatan/freegc/main.go:8) XORL AX, AX
0x001e 00030 (/home/yukatan/freegc/main.go:8) XORL CX, CX
0x0020 00032 (/home/yukatan/freegc/main.go:8) JMP 45
0x0022 00034 (/home/yukatan/freegc/main.go:9) MOVQ DX, -8(R8)(BX*8)
0x0027 00039 (/home/yukatan/freegc/main.go:8) INCQ DX
0x002a 00042 (/home/yukatan/freegc/main.go:8) MOVQ BX, CX
0x002d 00045 (/home/yukatan/freegc/main.go:8) CMPQ DX, $10000
0x0034 00052 (/home/yukatan/freegc/main.go:8) JGE 158
0x0036 00054 (/home/yukatan/freegc/main.go:9) LEAQ 1(CX), BX
0x003a 00058 (/home/yukatan/freegc/main.go:9) CMPQ AX, BX
0x003d 00061 (/home/yukatan/freegc/main.go:9) JCC 34
0x003f 00063 (/home/yukatan/freegc/main.go:8) MOVQ DX, main.i+72(SP)
0x0044 00068 (/home/yukatan/freegc/main.go:8) MOVB R9B, main..autotmp_8+71(SP)
0x0049 00073 (/home/yukatan/freegc/main.go:9) CMPQ BX, $4
0x004d 00077 (/home/yukatan/freegc/main.go:9) JGT 116
0x004f 00079 (/home/yukatan/freegc/main.go:8) TESTB R9B, R9B
0x0052 00082 (/home/yukatan/freegc/main.go:9) JNE 116
0x0054 00084 (/home/yukatan/freegc/main.go:9) TESTQ CX, CX
0x0057 00087 (/home/yukatan/freegc/main.go:9) JNE 116
0x0059 00089 (/home/yukatan/freegc/main.go:9) LEAQ main..autotmp_3+80(SP), R8
0x005e 00094 (/home/yukatan/freegc/main.go:9) MOVUPS X15, (R8)
0x0062 00098 (/home/yukatan/freegc/main.go:9) MOVUPS X15, 16(R8)
0x0067 00103 (/home/yukatan/freegc/main.go:9) MOVL $4, AX
0x006c 00108 (/home/yukatan/freegc/main.go:9) MOVL $1, R9
0x0072 00114 (/home/yukatan/freegc/main.go:9) JMP 34
0x0074 00116 (/home/yukatan/freegc/main.go:9) MOVQ AX, CX
0x0077 00119 (/home/yukatan/freegc/main.go:9) MOVL $1, DI
0x007c 00124 (/home/yukatan/freegc/main.go:9) LEAQ type:int(SB), SI
0x0083 00131 (/home/yukatan/freegc/main.go:9) MOVQ R8, AX
0x0086 00134 (/home/yukatan/freegc/main.go:9) PCDATA $1, $0
0x0086 00134 (/home/yukatan/freegc/main.go:9) CALL runtime.growslice(SB)
0x008b 00139 (/home/yukatan/freegc/main.go:9) MOVQ main.i+72(SP), DX
0x0090 00144 (/home/yukatan/freegc/main.go:9) MOVQ AX, R8
0x0093 00147 (/home/yukatan/freegc/main.go:9) MOVQ CX, AX
0x0096 00150 (/home/yukatan/freegc/main.go:9) MOVBLZX main..autotmp_8+71(SP), R9
0x009c 00156 (/home/yukatan/freegc/main.go:9) JMP 34
0x009e 00158 (/home/yukatan/freegc/main.go:11) ADDQ $112, SP
0x00a2 00162 (/home/yukatan/freegc/main.go:11) POPQ BP
0x00a3 00163 (/home/yukatan/freegc/main.go:11) RET
0x00a4 00164 (/home/yukatan/freegc/main.go:11) NOP
0x00a4 00164 (/home/yukatan/freegc/main.go:5) PCDATA $1, $-1
0x00a4 00164 (/home/yukatan/freegc/main.go:5) PCDATA $0, $-2
0x00a4 00164 (/home/yukatan/freegc/main.go:5) CALL runtime.morestack_noctxt(SB)
0x00a9 00169 (/home/yukatan/freegc/main.go:5) PCDATA $0, $-1
0x00a9 00169 (/home/yukatan/freegc/main.go:5) JMP 0
...
Moreover, the corresponding tests are not passed:
$ cd $GOROOT/src/cmd/compile/internal/test
$ GOEXPERIMENT=runtimefreegc go test -run=FreeAppendAllocations -v
=== RUN TestFreeAppendAllocations
=== RUN TestFreeAppendAllocations/slice-no-alias
free_test.go:34: allocs: 5
free_test.go:36: allocs: 5, want 1
=== RUN TestFreeAppendAllocations/slice-aliased
free_test.go:50: allocs: 5
--- FAIL: TestFreeAppendAllocations (0.00s)
--- FAIL: TestFreeAppendAllocations/slice-no-alias (0.00s)
--- PASS: TestFreeAppendAllocations/slice-aliased (0.00s)
FAIL
exit status 1
FAIL cmd/compile/internal/test 0.003s
What did you expect to see?
I suppose that goexperiment.RuntimeFreegc is always false for the compiler, and we should use buildcfg.Experiment.RuntimeFreegc in the corresponding files (ssa.go, escape.go) instead. With this fix, everything works good:
$ GOEXPERIMENT=runtimefreegc go build -gcflags='-S' -o /dev/null ./main.go
main.main STEXT size=174 align=0x0 args=0x0 locals=0x78 funcid=0x0
0x0000 00000 (/home/yukatan/freegc/main.go:5) TEXT main.main(SB), ABIInternal, $120-0
0x0000 00000 (/home/yukatan/freegc/main.go:5) CMPQ SP, 16(R14)
0x0004 00004 (/home/yukatan/freegc/main.go:5) PCDATA $0, $-2
0x0004 00004 (/home/yukatan/freegc/main.go:5) JLS 164
....
0x0072 00114 (/home/yukatan/freegc/main.go:9) JMP 34
0x0074 00116 (/home/yukatan/freegc/main.go:9) MOVQ AX, CX
0x0077 00119 (/home/yukatan/freegc/main.go:9) MOVL $1, DI
0x007c 00124 (/home/yukatan/freegc/main.go:9) LEAQ type:int(SB), SI
0x0083 00131 (/home/yukatan/freegc/main.go:9) MOVQ R8, AX
0x0086 00134 (/home/yukatan/freegc/main.go:9) PCDATA $1, $0
0x0086 00134 (/home/yukatan/freegc/main.go:9) CALL runtime.growsliceNoAlias(SB)
0x008b 00139 (/home/yukatan/freegc/main.go:9) MOVQ main.i+72(SP), DX
0x0090 00144 (/home/yukatan/freegc/main.go:9) MOVQ AX, R8
0x0093 00147 (/home/yukatan/freegc/main.go:9) MOVQ CX, AX
...
$ cd $GOROOT/src/cmd/compile/internal/test
$ GOEXPERIMENT=runtimefreegc go test -run=FreeAppendAllocations -v
=== RUN TestFreeAppendAllocations
=== RUN TestFreeAppendAllocations/slice-no-alias
free_test.go:34: allocs: 1
=== RUN TestFreeAppendAllocations/slice-aliased
free_test.go:50: allocs: 5
--- PASS: TestFreeAppendAllocations (0.00s)
--- PASS: TestFreeAppendAllocations/slice-no-alias (0.00s)
--- PASS: TestFreeAppendAllocations/slice-aliased (0.00s)
PASS
ok cmd/compile/internal/test 0.003s
Go version
go version go1.27-devel_24ec7d2120 Fri May 22 20:16:59 2026 -0700 linux/amd64
Output of
go envin your module/workspace:What did you do?
Consider the following example:
I compiled this one with the
GOEXPERIMENT=runtimefreegcenabled:What did you see happen?
Nothing happened, no calls to
runtime.growsliceNoAliaswere generated:Moreover, the corresponding tests are not passed:
What did you expect to see?
I suppose that
goexperiment.RuntimeFreegcis always false for the compiler, and we should usebuildcfg.Experiment.RuntimeFreegcin the corresponding files (ssa.go, escape.go) instead. With this fix, everything works good: