diff options
author | Matthew Dempsky <mdempsky@google.com> | 2021-06-30 18:19:26 -0700 |
---|---|---|
committer | Matthew Dempsky <mdempsky@google.com> | 2021-06-30 18:28:34 -0700 |
commit | ad7e5b219e3b4b2fe9775c946e427057154c1c33 (patch) | |
tree | 8eb732ac0b95c5827b5b2e71b278db1525460539 /src/cmd | |
parent | 8767b87ab54acca33c487ee46e237049b663b1c4 (diff) | |
parent | 4711bf30e5fec4cf290964785871deba5955c29a (diff) | |
download | go-ad7e5b219e3b4b2fe9775c946e427057154c1c33.tar.gz go-ad7e5b219e3b4b2fe9775c946e427057154c1c33.zip |
[dev.typeparams] all: merge master (4711bf3) into dev.typeparams
Conflicts:
- src/cmd/compile/internal/walk/builtin.go
On dev.typeparams, CL 330194 changed OCHECKNIL to not require manual
SetTypecheck(1) anymore; while on master, CL 331070 got rid of the
OCHECKNIL altogether by moving the check into the runtime support
functions.
- src/internal/buildcfg/exp.go
On master, CL 331109 refactored the logic for parsing the
GOEXPERIMENT string, so that it could be more easily reused by
cmd/go; while on dev.typeparams, several CLs tweaked the regabi
experiment defaults.
Merge List:
+ 2021-06-30 4711bf30e5 doc/go1.17: linkify "language changes" in the runtime section
+ 2021-06-30 ed56ea73e8 path/filepath: deflake TestEvalSymlinksAboveRoot on darwin
+ 2021-06-30 c080d0323b cmd/dist: pass -Wno-unknown-warning-option in swig_callback_lto
+ 2021-06-30 7d0e9e6e74 image/gif: fix typo in the comment (io.ReadByte -> io.ByteReader)
+ 2021-06-30 0fa3265fe1 os: change example to avoid deprecated function
+ 2021-06-30 d19a53338f image: add Uniform.RGBA64At and Rectangle.RGBA64At
+ 2021-06-30 c45e800e0c crypto/x509: don't fail on optional auth key id fields
+ 2021-06-29 f9d50953b9 net: fix failure of TestCVE202133195
+ 2021-06-29 e294b8a49e doc/go1.17: fix typo "MacOS" -> "macOS"
+ 2021-06-29 3463852b76 math/big: fix typo of comment (`BytesScanner` to `ByteScanner`)
+ 2021-06-29 fd4b587da3 cmd/compile: suppress details error for invalid variadic argument type
+ 2021-06-29 e2e05af6e1 cmd/internal/obj/arm64: fix an encoding error of CMPW instruction
+ 2021-06-28 4bb0847b08 cmd/compile,runtime: change unsafe.Slice((*T)(nil), 0) to return []T(nil)
+ 2021-06-28 1519271a93 spec: change unsafe.Slice((*T)(nil), 0) to return []T(nil)
+ 2021-06-28 5385e2386b runtime/internal/atomic: drop Cas64 pointer indirection in comments
+ 2021-06-28 956c81bfe6 cmd/go: add GOEXPERIMENT to `go env` output
+ 2021-06-28 a1d27269d6 cmd/go: prep for 'go env' refactoring
+ 2021-06-28 901510ed4e cmd/link/internal/ld: skip the windows ASLR test when CGO_ENABLED=0
+ 2021-06-28 361159c055 cmd/cgo: fix 'see gmp.go' to 'see doc.go'
+ 2021-06-27 c95464f0ea internal/buildcfg: refactor GOEXPERIMENT parsing code somewhat
+ 2021-06-25 ed01ceaf48 runtime/race: use race build tag on syso_test.go
+ 2021-06-25 d1916e5e84 go/types: in TestCheck/issues.src, import regexp/syntax instead of cmd/compile/internal/syntax
+ 2021-06-25 5160896c69 go/types: in TestStdlib, import from source instead of export data
+ 2021-06-25 d01bc571f7 runtime: make ncgocall a global counter
Change-Id: I1ce4a3b3ff7c824c67ad66dd27d9d5f1d25c0023
Diffstat (limited to 'src/cmd')
-rw-r--r-- | src/cmd/asm/internal/asm/testdata/arm64.s | 3 | ||||
-rw-r--r-- | src/cmd/cgo/main.go | 2 | ||||
-rw-r--r-- | src/cmd/compile/internal/typecheck/builtin.go | 5 | ||||
-rw-r--r-- | src/cmd/compile/internal/typecheck/builtin/runtime.go | 5 | ||||
-rw-r--r-- | src/cmd/compile/internal/typecheck/func.go | 7 | ||||
-rw-r--r-- | src/cmd/compile/internal/typecheck/typecheck.go | 17 | ||||
-rw-r--r-- | src/cmd/compile/internal/walk/builtin.go | 25 | ||||
-rw-r--r-- | src/cmd/dist/test.go | 6 | ||||
-rw-r--r-- | src/cmd/go/alldocs.go | 6 | ||||
-rw-r--r-- | src/cmd/go/internal/cfg/cfg.go | 2 | ||||
-rw-r--r-- | src/cmd/go/internal/envcmd/env.go | 218 | ||||
-rw-r--r-- | src/cmd/go/internal/help/helpdoc.go | 6 | ||||
-rw-r--r-- | src/cmd/go/main.go | 64 | ||||
-rw-r--r-- | src/cmd/go/testdata/script/env_exp.txt | 17 | ||||
-rw-r--r-- | src/cmd/go/testdata/script/env_unset.txt | 30 | ||||
-rw-r--r-- | src/cmd/go/testdata/script/env_write.txt | 6 | ||||
-rw-r--r-- | src/cmd/internal/obj/arm64/asm7.go | 4 | ||||
-rw-r--r-- | src/cmd/link/internal/ld/ld_test.go | 2 |
18 files changed, 266 insertions, 159 deletions
diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s index 5f1e68545b..d8a20edfc1 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64.s +++ b/src/cmd/asm/internal/asm/testdata/arm64.s @@ -89,7 +89,7 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8 CMP R1<<33, R2 CMP R22.SXTX, RSP // ffe336eb CMP $0x22220000, RSP // CMP $572653568, RSP // 5b44a4d2ff633beb - CMPW $0x22220000, RSP // CMPW $572653568, RSP // 5b44a452ff633b6b + CMPW $0x22220000, RSP // CMPW $572653568, RSP // 5b44a452ff433b6b CCMN MI, ZR, R1, $4 // e44341ba // MADD Rn,Rm,Ra,Rd MADD R1, R2, R3, R4 // 6408019b @@ -377,6 +377,7 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8 MOVD $0x1000100010001000, RSP // MOVD $1152939097061330944, RSP // ff8304b2 MOVW $0x10001000, RSP // MOVW $268439552, RSP // ff830432 ADDW $0x10001000, R1 // ADDW $268439552, R1 // fb83043221001b0b + ADDW $0x22220000, RSP, R3 // ADDW $572653568, RSP, R3 // 5b44a452e3433b0b // move a large constant to a Vd. VMOVS $0x80402010, V11 // VMOVS $2151686160, V11 diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go index 03a662e689..c6a0c525e6 100644 --- a/src/cmd/cgo/main.go +++ b/src/cmd/cgo/main.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Cgo; see gmp.go for an overview. +// Cgo; see doc.go for an overview. // TODO(rsc): // Emit correct line number annotations. diff --git a/src/cmd/compile/internal/typecheck/builtin.go b/src/cmd/compile/internal/typecheck/builtin.go index 67a894c7ed..833b17b414 100644 --- a/src/cmd/compile/internal/typecheck/builtin.go +++ b/src/cmd/compile/internal/typecheck/builtin.go @@ -138,6 +138,7 @@ var runtimeDecls = [...]struct { {"growslice", funcTag, 116}, {"unsafeslice", funcTag, 117}, {"unsafeslice64", funcTag, 118}, + {"unsafeslicecheckptr", funcTag, 118}, {"memmove", funcTag, 119}, {"memclrNoHeapPointers", funcTag, 120}, {"memclrHasPointers", funcTag, 120}, @@ -341,8 +342,8 @@ func runtimeTypes() []*types.Type { typs[114] = newSig(params(typs[1], typs[15], typs[15], typs[7]), params(typs[7])) typs[115] = types.NewSlice(typs[2]) typs[116] = newSig(params(typs[1], typs[115], typs[15]), params(typs[115])) - typs[117] = newSig(params(typs[1], typs[15]), nil) - typs[118] = newSig(params(typs[1], typs[22]), nil) + typs[117] = newSig(params(typs[1], typs[7], typs[15]), nil) + typs[118] = newSig(params(typs[1], typs[7], typs[22]), nil) typs[119] = newSig(params(typs[3], typs[3], typs[5]), nil) typs[120] = newSig(params(typs[7], typs[5]), nil) typs[121] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6])) diff --git a/src/cmd/compile/internal/typecheck/builtin/runtime.go b/src/cmd/compile/internal/typecheck/builtin/runtime.go index ebeaeae79e..2b29ea3c08 100644 --- a/src/cmd/compile/internal/typecheck/builtin/runtime.go +++ b/src/cmd/compile/internal/typecheck/builtin/runtime.go @@ -183,8 +183,9 @@ func makeslice(typ *byte, len int, cap int) unsafe.Pointer func makeslice64(typ *byte, len int64, cap int64) unsafe.Pointer func makeslicecopy(typ *byte, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer func growslice(typ *byte, old []any, cap int) (ary []any) -func unsafeslice(typ *byte, len int) -func unsafeslice64(typ *byte, len int64) +func unsafeslice(typ *byte, ptr unsafe.Pointer, len int) +func unsafeslice64(typ *byte, ptr unsafe.Pointer, len int64) +func unsafeslicecheckptr(typ *byte, ptr unsafe.Pointer, len int64) func memmove(to *any, frm *any, length uintptr) func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr) diff --git a/src/cmd/compile/internal/typecheck/func.go b/src/cmd/compile/internal/typecheck/func.go index 5f9f8c6ebd..d0aad5ac07 100644 --- a/src/cmd/compile/internal/typecheck/func.go +++ b/src/cmd/compile/internal/typecheck/func.go @@ -961,7 +961,14 @@ func tcUnsafeSlice(n *ir.BinaryExpr) *ir.BinaryExpr { t := n.X.Type() if !t.IsPtr() { base.Errorf("first argument to unsafe.Slice must be pointer; have %L", t) + } else if t.Elem().NotInHeap() { + // TODO(mdempsky): This can be relaxed, but should only affect the + // Go runtime itself. End users should only see //go:notinheap + // types due to incomplete C structs in cgo, and those types don't + // have a meaningful size anyway. + base.Errorf("unsafe.Slice of incomplete (or unallocatable) type not allowed") } + if !checkunsafeslice(&n.Y) { n.SetType(nil) return n diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go index 232c0e66ef..21d3100f66 100644 --- a/src/cmd/compile/internal/typecheck/typecheck.go +++ b/src/cmd/compile/internal/typecheck/typecheck.go @@ -1471,15 +1471,22 @@ toomany: } func errorDetails(nl ir.Nodes, tstruct *types.Type, isddd bool) string { - // If we don't know any type at a call site, let's suppress any return - // message signatures. See Issue https://golang.org/issues/19012. + // Suppress any return message signatures if: + // + // (1) We don't know any type at a call site (see #19012). + // (2) Any node has an unknown type. + // (3) Invalid type for variadic parameter (see #46957). if tstruct == nil { - return "" + return "" // case 1 } - // If any node has an unknown type, suppress it as well + + if isddd && !nl[len(nl)-1].Type().IsSlice() { + return "" // case 3 + } + for _, n := range nl { if n.Type() == nil { - return "" + return "" // case 2 } } return fmt.Sprintf("\n\thave %s\n\twant %v", fmtSignature(nl, isddd), tstruct) diff --git a/src/cmd/compile/internal/walk/builtin.go b/src/cmd/compile/internal/walk/builtin.go index 135eaee6bc..e1a2319e14 100644 --- a/src/cmd/compile/internal/walk/builtin.go +++ b/src/cmd/compile/internal/walk/builtin.go @@ -647,35 +647,28 @@ func walkRecoverFP(nn *ir.CallExpr, init *ir.Nodes) ir.Node { } func walkUnsafeSlice(n *ir.BinaryExpr, init *ir.Nodes) ir.Node { + ptr := safeExpr(n.X, init) len := safeExpr(n.Y, init) fnname := "unsafeslice64" - argtype := types.Types[types.TINT64] + lenType := types.Types[types.TINT64] // Type checking guarantees that TIDEAL len/cap are positive and fit in an int. // The case of len or cap overflow when converting TUINT or TUINTPTR to TINT // will be handled by the negative range checks in unsafeslice during runtime. - if len.Type().IsKind(types.TIDEAL) || len.Type().Size() <= types.Types[types.TUINT].Size() { + if ir.ShouldCheckPtr(ir.CurFunc, 1) { + fnname = "unsafeslicecheckptr" + // for simplicity, unsafeslicecheckptr always uses int64 + } else if len.Type().IsKind(types.TIDEAL) || len.Type().Size() <= types.Types[types.TUINT].Size() { fnname = "unsafeslice" - argtype = types.Types[types.TINT] + lenType = types.Types[types.TINT] } t := n.Type() - // Call runtime.unsafeslice[64] to check that the length argument is - // non-negative and smaller than the max length allowed for the - // element type. + // Call runtime.unsafeslice{,64,checkptr} to check ptr and len. fn := typecheck.LookupRuntime(fnname) - init.Append(mkcall1(fn, nil, init, reflectdata.TypePtr(t.Elem()), typecheck.Conv(len, argtype))) - - ptr := walkExpr(n.X, init) - - check := ir.NewUnaryExpr(n.Pos(), ir.OCHECKNIL, ptr) - init.Append(typecheck.Stmt(check)) - - // TODO(mdempsky): checkptr instrumentation. Maybe merge into length - // check above, along with nil check? Need to be careful about - // notinheap pointers though: can't pass them as unsafe.Pointer. + init.Append(mkcall1(fn, nil, init, reflectdata.TypePtr(t.Elem()), typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR]), typecheck.Conv(len, lenType))) h := ir.NewSliceHeaderExpr(n.Pos(), t, typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR]), diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index f2c4cf0b43..4acd357974 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -737,9 +737,9 @@ func (t *tester) registerTests() { fn: func(dt *distTest) error { cmd := t.addCmd(dt, "misc/swig/callback", t.goTest()) cmd.Env = append(os.Environ(), - "CGO_CFLAGS=-flto -Wno-lto-type-mismatch", - "CGO_CXXFLAGS=-flto -Wno-lto-type-mismatch", - "CGO_LDFLAGS=-flto -Wno-lto-type-mismatch", + "CGO_CFLAGS=-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option", + "CGO_CXXFLAGS=-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option", + "CGO_LDFLAGS=-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option", ) return nil }, diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index fd95da23eb..90eb3e2a00 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -1903,6 +1903,12 @@ // GCCGOTOOLDIR // If set, where to find gccgo tools, such as cgo. // The default is based on how gccgo was configured. +// GOEXPERIMENT +// Comma-separated list of toolchain experiments to enable or disable. +// The list of available experiments may change arbitrarily over time. +// See src/internal/goexperiment/flags.go for currently valid values. +// Warning: This variable is provided for the development and testing +// of the Go toolchain itself. Use beyond that purpose is unsupported. // GOROOT_FINAL // The root of the installed Go tree, when it is // installed in a location other than where it is built. diff --git a/src/cmd/go/internal/cfg/cfg.go b/src/cmd/go/internal/cfg/cfg.go index fc6989097e..57a3c1ff6f 100644 --- a/src/cmd/go/internal/cfg/cfg.go +++ b/src/cmd/go/internal/cfg/cfg.go @@ -79,7 +79,7 @@ func defaultContext() build.Context { // The experiments flags are based on GOARCH, so they may // need to change. TODO: This should be cleaned up. - buildcfg.UpdateExperiments(ctxt.GOARCH) + buildcfg.UpdateExperiments(ctxt.GOOS, ctxt.GOARCH, envOr("GOEXPERIMENT", buildcfg.DefaultGOEXPERIMENT)) ctxt.ToolTags = nil for _, exp := range buildcfg.EnabledExperiments() { ctxt.ToolTags = append(ctxt.ToolTags, "goexperiment."+exp) diff --git a/src/cmd/go/internal/envcmd/env.go b/src/cmd/go/internal/envcmd/env.go index b30c37ab27..1553d26391 100644 --- a/src/cmd/go/internal/envcmd/env.go +++ b/src/cmd/go/internal/envcmd/env.go @@ -10,6 +10,7 @@ import ( "encoding/json" "fmt" "go/build" + "internal/buildcfg" "io" "os" "path/filepath" @@ -72,6 +73,7 @@ func MkEnv() []cfg.EnvVar { {Name: "GOCACHE", Value: cache.DefaultDir()}, {Name: "GOENV", Value: envFile}, {Name: "GOEXE", Value: cfg.ExeSuffix}, + {Name: "GOEXPERIMENT", Value: buildcfg.GOEXPERIMENT()}, {Name: "GOFLAGS", Value: cfg.Getenv("GOFLAGS")}, {Name: "GOHOSTARCH", Value: runtime.GOARCH}, {Name: "GOHOSTOS", Value: runtime.GOOS}, @@ -197,6 +199,21 @@ func runEnv(ctx context.Context, cmd *base.Command, args []string) { if *envU && *envW { base.Fatalf("go env: cannot use -u with -w") } + + // Handle 'go env -w' and 'go env -u' before calling buildcfg.Check, + // so they can be used to recover from an invalid configuration. + if *envW { + runEnvW(args) + return + } + + if *envU { + runEnvU(args) + return + } + + buildcfg.Check() + env := cfg.CmdEnv env = append(env, ExtraEnvVars()...) @@ -206,14 +223,7 @@ func runEnv(ctx context.Context, cmd *base.Command, args []string) { // Do we need to call ExtraEnvVarsCostly, which is a bit expensive? needCostly := false - if *envU || *envW { - // We're overwriting or removing default settings, - // so it doesn't really matter what the existing settings are. - // - // Moreover, we haven't validated the new settings yet, so it is - // important that we NOT perform any actions based on them, - // such as initializing the builder to compute other variables. - } else if len(args) == 0 { + if len(args) == 0 { // We're listing all environment variables ("go env"), // including the expensive ones. needCostly = true @@ -238,95 +248,6 @@ func runEnv(ctx context.Context, cmd *base.Command, args []string) { env = append(env, ExtraEnvVarsCostly()...) } - if *envW { - // Process and sanity-check command line. - if len(args) == 0 { - base.Fatalf("go env -w: no KEY=VALUE arguments given") - } - osEnv := make(map[string]string) - for _, e := range cfg.OrigEnv { - if i := strings.Index(e, "="); i >= 0 { - osEnv[e[:i]] = e[i+1:] - } - } - add := make(map[string]string) - for _, arg := range args { - i := strings.Index(arg, "=") - if i < 0 { - base.Fatalf("go env -w: arguments must be KEY=VALUE: invalid argument: %s", arg) - } - key, val := arg[:i], arg[i+1:] - if err := checkEnvWrite(key, val); err != nil { - base.Fatalf("go env -w: %v", err) - } - if _, ok := add[key]; ok { - base.Fatalf("go env -w: multiple values for key: %s", key) - } - add[key] = val - if osVal := osEnv[key]; osVal != "" && osVal != val { - fmt.Fprintf(os.Stderr, "warning: go env -w %s=... does not override conflicting OS environment variable\n", key) - } - } - - goos, okGOOS := add["GOOS"] - goarch, okGOARCH := add["GOARCH"] - if okGOOS || okGOARCH { - if !okGOOS { - goos = cfg.Goos - } - if !okGOARCH { - goarch = cfg.Goarch - } - if err := work.CheckGOOSARCHPair(goos, goarch); err != nil { - base.Fatalf("go env -w: %v", err) - } - } - - gotmp, okGOTMP := add["GOTMPDIR"] - if okGOTMP { - if !filepath.IsAbs(gotmp) && gotmp != "" { - base.Fatalf("go env -w: GOTMPDIR must be an absolute path") - } - } - - updateEnvFile(add, nil) - return - } - - if *envU { - // Process and sanity-check command line. - if len(args) == 0 { - base.Fatalf("go env -u: no arguments given") - } - del := make(map[string]bool) - for _, arg := range args { - if err := checkEnvWrite(arg, ""); err != nil { - base.Fatalf("go env -u: %v", err) - } - del[arg] = true - } - if del["GOOS"] || del["GOARCH"] { - goos, goarch := cfg.Goos, cfg.Goarch - if del["GOOS"] { - goos = getOrigEnv("GOOS") - if goos == "" { - goos = build.Default.GOOS - } - } - if del["GOARCH"] { - goarch = getOrigEnv("GOARCH") - if goarch == "" { - goarch = build.Default.GOARCH - } - } - if err := work.CheckGOOSARCHPair(goos, goarch); err != nil { - base.Fatalf("go env -u: %v", err) - } - } - updateEnvFile(nil, del) - return - } - if len(args) > 0 { if *envJson { var es []cfg.EnvVar @@ -351,6 +272,109 @@ func runEnv(ctx context.Context, cmd *base.Command, args []string) { PrintEnv(os.Stdout, env) } +func runEnvW(args []string) { + // Process and sanity-check command line. + if len(args) == 0 { + base.Fatalf("go env -w: no KEY=VALUE arguments given") + } + osEnv := make(map[string]string) + for _, e := range cfg.OrigEnv { + if i := strings.Index(e, "="); i >= 0 { + osEnv[e[:i]] = e[i+1:] + } + } + add := make(map[string]string) + for _, arg := range args { + i := strings.Index(arg, "=") + if i < 0 { + base.Fatalf("go env -w: arguments must be KEY=VALUE: invalid argument: %s", arg) + } + key, val := arg[:i], arg[i+1:] + if err := checkEnvWrite(key, val); err != nil { + base.Fatalf("go env -w: %v", err) + } + if _, ok := add[key]; ok { + base.Fatalf("go env -w: multiple values for key: %s", key) + } + add[key] = val + if osVal := osEnv[key]; osVal != "" && osVal != val { + fmt.Fprintf(os.Stderr, "warning: go env -w %s=... does not override conflicting OS environment variable\n", key) + } + } + + if err := checkBuildConfig(add, nil); err != nil { + base.Fatalf("go env -w: %v", err) + } + + gotmp, okGOTMP := add["GOTMPDIR"] + if okGOTMP { + if !filepath.IsAbs(gotmp) && gotmp != "" { + base.Fatalf("go env -w: GOTMPDIR must be an absolute path") + } + } + + updateEnvFile(add, nil) +} + +func runEnvU(args []string) { + // Process and sanity-check command line. + if len(args) == 0 { + base.Fatalf("go env -u: no arguments given") + } + del := make(map[string]bool) + for _, arg := range args { + if err := checkEnvWrite(arg, ""); err != nil { + base.Fatalf("go env -u: %v", err) + } + del[arg] = true + } + + if err := checkBuildConfig(nil, del); err != nil { + base.Fatalf("go env -u: %v", err) + } + + updateEnvFile(nil, del) +} + +// checkBuildConfig checks whether the build configuration is valid +// after the specified configuration environment changes are applied. +func checkBuildConfig(add map[string]string, del map[string]bool) error { + // get returns the value for key after applying add and del and + // reports whether it changed. cur should be the current value + // (i.e., before applying changes) and def should be the default + // value (i.e., when no environment variables are provided at all). + get := func(key, cur, def string) (string, bool) { + if val, ok := add[key]; ok { + return val, true + } + if del[key] { + val := getOrigEnv(key) + if val == "" { + val = def + } + return val, true + } + return cur, false + } + + goos, okGOOS := get("GOOS", cfg.Goos, build.Default.GOOS) + goarch, okGOARCH := get("GOARCH", cfg.Goarch, build.Default.GOARCH) + if okGOOS || okGOARCH { + if err := work.CheckGOOSARCHPair(goos, goarch); err != nil { + return err + } + } + + goexperiment, okGOEXPERIMENT := get("GOEXPERIMENT", buildcfg.GOEXPERIMENT(), "") + if okGOEXPERIMENT { + if _, _, err := buildcfg.ParseGOEXPERIMENT(goos, goarch, goexperiment); err != nil { + return err + } + } + + return nil +} + // PrintEnv prints the environment variables to w. func PrintEnv(w io.Writer, env []cfg.EnvVar) { for _, e := range env { diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go index b552777e3e..490ff1fb7c 100644 --- a/src/cmd/go/internal/help/helpdoc.go +++ b/src/cmd/go/internal/help/helpdoc.go @@ -610,6 +610,12 @@ Special-purpose environment variables: GCCGOTOOLDIR If set, where to find gccgo tools, such as cgo. The default is based on how gccgo was configured. + GOEXPERIMENT + Comma-separated list of toolchain experiments to enable or disable. + The list of available experiments may change arbitrarily over time. + See src/internal/goexperiment/flags.go for currently valid values. + Warning: This variable is provided for the development and testing + of the Go toolchain itself. Use beyond that purpose is unsupported. GOROOT_FINAL The root of the installed Go tree, when it is installed in a location other than where it is built. diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go index 02174a56ff..16361e02ca 100644 --- a/src/cmd/go/main.go +++ b/src/cmd/go/main.go @@ -145,24 +145,6 @@ func main() { os.Exit(2) } - if err := buildcfg.Error; err != nil { - fmt.Fprintf(os.Stderr, "go: %v\n", buildcfg.Error) - os.Exit(2) - } - - // Set environment (GOOS, GOARCH, etc) explicitly. - // In theory all the commands we invoke should have - // the same default computation of these as we do, - // but in practice there might be skew - // This makes sure we all agree. - cfg.OrigEnv = os.Environ() - cfg.CmdEnv = envcmd.MkEnv() - for _, env := range cfg.CmdEnv { - if os.Getenv(env.Name) != env.Value { - os.Setenv(env.Name, env.Value) - } - } - BigCmdLoop: for bigCmd := base.Go; ; { for _, cmd := range bigCmd.Commands { @@ -188,18 +170,7 @@ BigCmdLoop: if !cmd.Runnable() { continue } - cmd.Flag.Usage = func() { cmd.Usage() } - if cmd.CustomFlags { - args = args[1:] - } else { - base.SetFromGOFLAGS(&cmd.Flag) - cmd.Flag.Parse(args[1:]) - args = cmd.Flag.Args() - } - ctx := maybeStartTrace(context.Background()) - ctx, span := trace.StartSpan(ctx, fmt.Sprint("Running ", cmd.Name(), " command")) - cmd.Run(ctx, cmd, args) - span.Done() + invoke(cmd, args) base.Exit() return } @@ -213,6 +184,39 @@ BigCmdLoop: } } +func invoke(cmd *base.Command, args []string) { + // 'go env' handles checking the build config + if cmd != envcmd.CmdEnv { + buildcfg.Check() + } + + // Set environment (GOOS, GOARCH, etc) explicitly. + // In theory all the commands we invoke should have + // the same default computation of these as we do, + // but in practice there might be skew + // This makes sure we all agree. + cfg.OrigEnv = os.Environ() + cfg.CmdEnv = envcmd.MkEnv() + for _, env := range cfg.CmdEnv { + if os.Getenv(env.Name) != env.Value { + os.Setenv(env.Name, env.Value) + } + } + + cmd.Flag.Usage = func() { cmd.Usage() } + if cmd.CustomFlags { + args = args[1:] + } else { + base.SetFromGOFLAGS(&cmd.Flag) + cmd.Flag.Parse(args[1:]) + args = cmd.Flag.Args() + } + ctx := maybeStartTrace(context.Background()) + ctx, span := trace.StartSpan(ctx, fmt.Sprint("Running ", cmd.Name(), " command")) + cmd.Run(ctx, cmd, args) + span.Done() +} + func init() { base.Usage = mainUsage } diff --git a/src/cmd/go/testdata/script/env_exp.txt b/src/cmd/go/testdata/script/env_exp.txt new file mode 100644 index 0000000000..681512d87c --- /dev/null +++ b/src/cmd/go/testdata/script/env_exp.txt @@ -0,0 +1,17 @@ +# Test GOEXPERIMENT variable + +# go env shows default empty GOEXPERIMENT +go env +stdout GOEXPERIMENT= + +# go env shows valid experiments +env GOEXPERIMENT=fieldtrack,staticlockranking +go env GOEXPERIMENT +stdout '.*fieldtrack.*staticlockranking.*' +go env +stdout 'GOEXPERIMENT=.*fieldtrack.*staticlockranking.*' + +# go env rejects unknown experiments +env GOEXPERIMENT=bad +! go env GOEXPERIMENT +stderr 'unknown GOEXPERIMENT bad' diff --git a/src/cmd/go/testdata/script/env_unset.txt b/src/cmd/go/testdata/script/env_unset.txt new file mode 100644 index 0000000000..4e0f249509 --- /dev/null +++ b/src/cmd/go/testdata/script/env_unset.txt @@ -0,0 +1,30 @@ +# Test that we can unset variables, even if initially invalid, +# as long as resulting config is valid. + +env GOENV=badenv +env GOOS= +env GOARCH= +env GOEXPERIMENT= + +! go env +stderr '^go(\.exe)?: unknown GOEXPERIMENT badexp$' + +go env -u GOEXPERIMENT + +! go env +stderr '^cmd/go: unsupported GOOS/GOARCH pair bados/badarch$' + +! go env -u GOOS +stderr '^go env -u: unsupported GOOS/GOARCH pair \w+/badarch$' + +! go env -u GOARCH +stderr '^go env -u: unsupported GOOS/GOARCH pair bados/\w+$' + +go env -u GOOS GOARCH + +go env + +-- badenv -- +GOOS=bados +GOARCH=badarch +GOEXPERIMENT=badexp diff --git a/src/cmd/go/testdata/script/env_write.txt b/src/cmd/go/testdata/script/env_write.txt index 4fa39df104..b5e9739167 100644 --- a/src/cmd/go/testdata/script/env_write.txt +++ b/src/cmd/go/testdata/script/env_write.txt @@ -179,3 +179,9 @@ stderr 'unsupported GOOS/GOARCH.*windows/mips$' stderr 'go env -w: GOMODCACHE entry is relative; must be absolute path: "~/test"' ! go env -w GOMODCACHE=./test stderr 'go env -w: GOMODCACHE entry is relative; must be absolute path: "./test"' + +# go env -w checks validity of GOEXPERIMENT +env GOEXPERIMENT= +! go env -w GOEXPERIMENT=badexp +stderr 'unknown GOEXPERIMENT badexp' +go env -w GOEXPERIMENT=fieldtrack diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go index b8c3cd97c7..d99afa3d27 100644 --- a/src/cmd/internal/obj/arm64/asm7.go +++ b/src/cmd/internal/obj/arm64/asm7.go @@ -4333,8 +4333,10 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { if p.To.Reg == REG_RSP && isADDSop(p.As) { c.ctxt.Diag("illegal destination register: %v\n", p) } + lsl0 := LSL0_64 if isADDWop(p.As) || isANDWop(p.As) { o1 = c.omovconst(AMOVW, p, &p.From, REGTMP) + lsl0 = LSL0_32 } else { o1 = c.omovconst(AMOVD, p, &p.From, REGTMP) } @@ -4350,7 +4352,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { if p.To.Reg == REGSP || r == REGSP { o2 = c.opxrrr(p, p.As, false) o2 |= REGTMP & 31 << 16 - o2 |= LSL0_64 + o2 |= uint32(lsl0) } else { o2 = c.oprrr(p, p.As) o2 |= REGTMP & 31 << 16 /* shift is 0 */ diff --git a/src/cmd/link/internal/ld/ld_test.go b/src/cmd/link/internal/ld/ld_test.go index ca764632c3..3702a4d08f 100644 --- a/src/cmd/link/internal/ld/ld_test.go +++ b/src/cmd/link/internal/ld/ld_test.go @@ -174,6 +174,8 @@ func TestWindowsBuildmodeCSharedASLR(t *testing.T) { t.Skip("skipping windows amd64/386 only test") } + testenv.MustHaveCGO(t) + t.Run("aslr", func(t *testing.T) { testWindowsBuildmodeCSharedASLR(t, true) }) |