Closed bigwhite closed 1 week ago
If we place const declaration block before var declaration block, the init order will become v0 -> v1 -> v2:
$go run main.go // go1.22.0
main: const c1 has been initialized
main: const c2 has been initialized
main: var v1 has been initialized
main: var v2 has been initialized
main: first init func invoked
main: second init func invoked
constInitCheck() has a dependency on c1 and c2, which are uninitialized at that point. variableInit has no dependency. this all appears consistent with the current spec.
@seankhliao thanks for instant reply. Go spec says "no dependencies on uninitialized variables" , but c1 and c2 are uninitialized constants. there is a little bit of inconsistency.
This looks like it changed between 1.21 and 1.22. I agree with the OP, constants are not variables. @gri
@griesemer
Change https://go.dev/cl/575075 mentions this issue: cmd/compile: put constants before variables in initialization order
Bisect points to https://go-review.googlesource.com/c/go/+/517617, switching to use types2 for init order, which makes sense. types2 always had this bug. FYI @mdempsky
[edit]: BTW, should this be backported? As it may cause some wrong initial values: https://go.dev/play/p/2HA4DR3_cjD
Just a curious BTW question: why is a
initialized after b
?
By my understanding of the spec, the order should be inverted.
package main
var x = 0
var a = foo()
var b = x
func foo() int {
x++
return x
}
func main() {
println(a, b) // 1 0
}
@go101 Thanks. Would you mind opening a separate issue for that? The gc compiler prints 1, 0
while gccgo prints 1, 1
.
Reopening for @griesemer to decide if anything needs to change in the spec.
@go101 I don't think this issue warrants backporting. The workaround is pretty easy.
@go101 Re: your question about this code:
package main
var x = 0
var a = foo()
var b = x
func foo() int {
x++
return x
}
func main() {
println(a, b) // 1 1 for Go 1.23
}
The result should be 1 1: x
is initialized first as it doesn't depend on any other variables and thus is ready for initialization and it's first in the source. Then a
is initialized: it depends on f
which depends on x
but x
is initialized, so f
can proceed and the result is 1 for a
. Then b
is set to the value of a
which is 1. This matches gccgo
.
With respect to the original issue, constants are never "initialized", they have their values already at compile time. The bug was fixed with CL 575075.
(Technical aside: constants appear in the implementation code determining initialization order only because that code is also used to detect invalid cycles among constant declarations; constants don't have an impact on initialization order. The bug was that constants were treated like variables w/o dependencies and thus their source order influenced the initialization order. The fix was to prioritize a constant always before any variable which effectively removes them from the initialization order - they are "pre-initialized" if you will.)
With respect to the spec: I don't think anything needs to change. The spec explicitly talks about variables, not constants in this context.
With respect to backporting: I think we should backport this. It's easy enough and it is a bug with respect to the spec.
Closing this issue as fixed but will create a backport issue.
@gopherbot please consider this for backport to 1.22, it's a bug with respect to the spec.
Backport issue(s) opened: #67820 (for 1.22).
Remember to create the cherry-pick CL(s) as soon as the patch is submitted to master, according to https://go.dev/wiki/MinorReleases.
Go version
go 1.22.0
Output of
go env
in your module/workspace:What did you do?
I have example below:
What did you see happen?
Compile and run the code in go 1.22.0,I got this output:
What did you expect to see?
According to the latest go spec:
v0、v1 and v2 all have initializaiton expression , and should be considered as "not ready for initialization"。their init order should be v0 -> v1 -> v2。but the real init order is v1 -> v2 -> v0。