aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMatthew Dempsky <mdempsky@google.com>2021-06-30 18:19:26 -0700
committerMatthew Dempsky <mdempsky@google.com>2021-06-30 18:28:34 -0700
commitad7e5b219e3b4b2fe9775c946e427057154c1c33 (patch)
tree8eb732ac0b95c5827b5b2e71b278db1525460539 /src
parent8767b87ab54acca33c487ee46e237049b663b1c4 (diff)
parent4711bf30e5fec4cf290964785871deba5955c29a (diff)
downloadgo-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')
-rw-r--r--src/cmd/asm/internal/asm/testdata/arm64.s3
-rw-r--r--src/cmd/cgo/main.go2
-rw-r--r--src/cmd/compile/internal/typecheck/builtin.go5
-rw-r--r--src/cmd/compile/internal/typecheck/builtin/runtime.go5
-rw-r--r--src/cmd/compile/internal/typecheck/func.go7
-rw-r--r--src/cmd/compile/internal/typecheck/typecheck.go17
-rw-r--r--src/cmd/compile/internal/walk/builtin.go25
-rw-r--r--src/cmd/dist/test.go6
-rw-r--r--src/cmd/go/alldocs.go6
-rw-r--r--src/cmd/go/internal/cfg/cfg.go2
-rw-r--r--src/cmd/go/internal/envcmd/env.go218
-rw-r--r--src/cmd/go/internal/help/helpdoc.go6
-rw-r--r--src/cmd/go/main.go64
-rw-r--r--src/cmd/go/testdata/script/env_exp.txt17
-rw-r--r--src/cmd/go/testdata/script/env_unset.txt30
-rw-r--r--src/cmd/go/testdata/script/env_write.txt6
-rw-r--r--src/cmd/internal/obj/arm64/asm7.go4
-rw-r--r--src/cmd/link/internal/ld/ld_test.go2
-rw-r--r--src/crypto/x509/parser.go8
-rw-r--r--src/crypto/x509/x509_test.go42
-rw-r--r--src/go/types/stdlib_test.go8
-rw-r--r--src/go/types/testdata/check/issues.src8
-rw-r--r--src/image/geom.go8
-rw-r--r--src/image/gif/reader.go2
-rw-r--r--src/image/image_test.go12
-rw-r--r--src/image/names.go5
-rw-r--r--src/internal/buildcfg/exp.go60
-rw-r--r--src/math/big/int.go2
-rw-r--r--src/net/dnsclient_unix_test.go8
-rw-r--r--src/os/example_test.go5
-rw-r--r--src/path/filepath/path_test.go11
-rw-r--r--src/runtime/cgocall.go2
-rw-r--r--src/runtime/checkptr.go21
-rw-r--r--src/runtime/checkptr_test.go2
-rw-r--r--src/runtime/debug.go2
-rw-r--r--src/runtime/internal/atomic/atomic_amd64.s2
-rw-r--r--src/runtime/internal/atomic/atomic_arm64.s2
-rw-r--r--src/runtime/internal/atomic/atomic_mips64x.s2
-rw-r--r--src/runtime/internal/atomic/atomic_ppc64x.s2
-rw-r--r--src/runtime/internal/atomic/atomic_riscv64.s3
-rw-r--r--src/runtime/proc.go2
-rw-r--r--src/runtime/race/syso_test.go10
-rw-r--r--src/runtime/slice.go24
-rw-r--r--src/runtime/testdata/testprog/checkptr.go13
-rw-r--r--src/unsafe/unsafe.go5
45 files changed, 476 insertions, 220 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.Comm