Skip to content

cmd/compile: global variable initialization done in unexpected order #51913

Closed
@jcp19

Description

@jcp19

What version of Go are you using (go version)?

$ go version
go version go1.16.4 darwin/amd64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/joao/Library/Caches/go-build"
GOENV="/Users/joao/Library/Application Support/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/joao/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/joao/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/Cellar/go/1.16.4/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/Cellar/go/1.16.4/libexec/pkg/tool/darwin_amd64"
GOVCS=""
GOVERSION="go1.16.4"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/dev/null"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/2d/wcw2b3c57jz69cl5tg_s2fx00000gn/T/go-build3928827666=/tmp/go-build -gno-record-gcc-switches -fno-common"
GOROOT/bin/go version: go version go1.16.4 darwin/amd64
GOROOT/bin/go tool compile -V: compile version go1.16.4
uname -v: Darwin Kernel Version 21.3.0: Wed Jan  5 21:37:58 PST 2022; root:xnu-8019.80.24~20/RELEASE_X86_64
ProductName:	macOS
ProductVersion:	12.2.1
BuildVersion:	21D62
lldb --version: lldb-1103.0.22.10
Apple Swift version 5.2.4 (swiftlang-1103.0.32.9 clang-1103.0.32.53)

What did you do?

I have a package consisting of the following two files:

f1.go

package main    
   
var A int = 3    
var B int = A + 1    
var C int = A

f2.go

package main    
   
import "fmt"    
                     
var D = f()      
   
func f() int {    
  A = 1    
  return 1    
}    
   
func main() {    
  fmt.Println(A, B, C)    
}  

What did you expect to see?

According to the Go language specification, "package-level variable initialization proceeds stepwise, with each step selecting the variable earliest in declaration order which has no dependencies on uninitialized variables".

As such, I would expect two possible orders in which the global variables can be initialized:

  1. A < B < C < D - happens when you compile the project by passing f1.go first to the compiler, followed by f2.go . In this case, the output is "1 4 3"
  2. A < D < B < C - happens when f2.go is passed first to the compiler. In this case, the expected output would be "1 2 1".

What did you see instead?

For the second case (when f2.go is passed first), the actual output is "1 2 3". If instead I rewrite file f1.go to the following, I get the expected output for case 2.

Rewritten f2.go

package main    
   
import "fmt"    
   
var A int = initA()    
var B int = initB()    
var C int = initC()    
     
func initA() int {    
  fmt.Println("Init A")    
  return 3    
}    
     
func initB() int {    
  fmt.Println("Init B")    
  return A + 1    
}    
 
func initC() int {    
  fmt.Println("Init C")    
  return A    
} 

Output

Init A
Init B
Init C
1 2 1

Additional Information

This issue was first discussed in the golang-nuts Google Group (link).

Metadata

Metadata

Assignees

Labels

FrozenDueToAgeNeedsFixThe path to resolution is known, but the work has not been done.compiler/runtimeIssues related to the Go compiler and/or runtime.early-in-cycleA change that should be done early in the 3 month dev cycle.

Type

No type

Projects

Status

Done

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions