[dev.inline] merge with master at 894d24d617

Change-Id: I845eec08108c69228ebcba921f8a807a376d3fae
diff --git a/api/go1.21.txt b/api/go1.21.txt
index 6435d10..c8ca3df 100644
--- a/api/go1.21.txt
+++ b/api/go1.21.txt
@@ -174,6 +174,7 @@
 pkg go/build, type Package struct, TestDirectives []Directive #56986
 pkg go/build, type Package struct, XTestDirectives []Directive #56986
 pkg go/token, method (*File) Lines() []int #57708
+pkg go/types, method (*Package) GoVersion() string #61175
 pkg html/template, const ErrJSTemplate = 12 #59584
 pkg html/template, const ErrJSTemplate ErrorCode #59584
 pkg io/fs, func FormatDirEntry(DirEntry) string #54451
diff --git a/src/cmd/asm/internal/lex/slice.go b/src/cmd/asm/internal/lex/slice.go
index 8ee0c70..61b15dd 100644
--- a/src/cmd/asm/internal/lex/slice.go
+++ b/src/cmd/asm/internal/lex/slice.go
@@ -65,7 +65,7 @@
 	//	#define A #define B(x) x
 	// and
 	//	#define A #define B (x) x
-	// The first has definition of B has an argument, the second doesn't. Because we let
+	// The first definition of B has an argument, the second doesn't. Because we let
 	// text/scanner strip the blanks for us, this is extremely rare, hard to fix, and not worth it.
 	return s.pos
 }
diff --git a/src/cmd/compile/internal/ssa/_gen/RISCV64.rules b/src/cmd/compile/internal/ssa/_gen/RISCV64.rules
index eb1f10d..9a6fceb 100644
--- a/src/cmd/compile/internal/ssa/_gen/RISCV64.rules
+++ b/src/cmd/compile/internal/ssa/_gen/RISCV64.rules
@@ -836,11 +836,11 @@
 //
 // Key:
 //
-//   [+ -](x * y) [+ -] z.
-//    _ N          A S
-//                 D U
-//                 D B
+//   [+ -](x * y [+ -] z).
+//    _ N         A S
+//                D U
+//                D B
 //
 // Note: multiplication commutativity handled by rule generator.
-(F(MADD|NMADD|MSUB|NMSUB)D neg:(FNEGD x) y z) && neg.Uses == 1 => (F(NMADD|MADD|NMSUB|MSUB)D x y z)
+(F(MADD|NMADD|MSUB|NMSUB)D neg:(FNEGD x) y z) && neg.Uses == 1 => (F(NMSUB|MSUB|NMADD|MADD)D x y z)
 (F(MADD|NMADD|MSUB|NMSUB)D x y neg:(FNEGD z)) && neg.Uses == 1 => (F(MSUB|NMSUB|MADD|NMADD)D x y z)
diff --git a/src/cmd/compile/internal/ssa/rewriteRISCV64.go b/src/cmd/compile/internal/ssa/rewriteRISCV64.go
index f1debe0..ffbeb1d 100644
--- a/src/cmd/compile/internal/ssa/rewriteRISCV64.go
+++ b/src/cmd/compile/internal/ssa/rewriteRISCV64.go
@@ -3322,7 +3322,7 @@
 	v_0 := v.Args[0]
 	// match: (FMADDD neg:(FNEGD x) y z)
 	// cond: neg.Uses == 1
-	// result: (FNMADDD x y z)
+	// result: (FNMSUBD x y z)
 	for {
 		for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
 			neg := v_0
@@ -3335,7 +3335,7 @@
 			if !(neg.Uses == 1) {
 				continue
 			}
-			v.reset(OpRISCV64FNMADDD)
+			v.reset(OpRISCV64FNMSUBD)
 			v.AddArg3(x, y, z)
 			return true
 		}
@@ -3367,7 +3367,7 @@
 	v_0 := v.Args[0]
 	// match: (FMSUBD neg:(FNEGD x) y z)
 	// cond: neg.Uses == 1
-	// result: (FNMSUBD x y z)
+	// result: (FNMADDD x y z)
 	for {
 		for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
 			neg := v_0
@@ -3380,7 +3380,7 @@
 			if !(neg.Uses == 1) {
 				continue
 			}
-			v.reset(OpRISCV64FNMSUBD)
+			v.reset(OpRISCV64FNMADDD)
 			v.AddArg3(x, y, z)
 			return true
 		}
@@ -3412,7 +3412,7 @@
 	v_0 := v.Args[0]
 	// match: (FNMADDD neg:(FNEGD x) y z)
 	// cond: neg.Uses == 1
-	// result: (FMADDD x y z)
+	// result: (FMSUBD x y z)
 	for {
 		for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
 			neg := v_0
@@ -3425,7 +3425,7 @@
 			if !(neg.Uses == 1) {
 				continue
 			}
-			v.reset(OpRISCV64FMADDD)
+			v.reset(OpRISCV64FMSUBD)
 			v.AddArg3(x, y, z)
 			return true
 		}
@@ -3457,7 +3457,7 @@
 	v_0 := v.Args[0]
 	// match: (FNMSUBD neg:(FNEGD x) y z)
 	// cond: neg.Uses == 1
-	// result: (FMSUBD x y z)
+	// result: (FMADDD x y z)
 	for {
 		for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
 			neg := v_0
@@ -3470,7 +3470,7 @@
 			if !(neg.Uses == 1) {
 				continue
 			}
-			v.reset(OpRISCV64FMSUBD)
+			v.reset(OpRISCV64FMADDD)
 			v.AddArg3(x, y, z)
 			return true
 		}
diff --git a/src/cmd/compile/internal/types2/check.go b/src/cmd/compile/internal/types2/check.go
index b2a9eb0..0a2a490 100644
--- a/src/cmd/compile/internal/types2/check.go
+++ b/src/cmd/compile/internal/types2/check.go
@@ -11,6 +11,7 @@
 	"errors"
 	"fmt"
 	"go/constant"
+	"internal/goversion"
 	. "internal/types/errors"
 )
 
@@ -231,19 +232,19 @@
 		info = new(Info)
 	}
 
-	version, err := parseGoVersion(conf.GoVersion)
-	if err != nil {
-		panic(fmt.Sprintf("invalid Go version %q (%v)", conf.GoVersion, err))
-	}
+	// Note: clients may call NewChecker with the Unsafe package, which is
+	// globally shared and must not be mutated. Therefore NewChecker must not
+	// mutate *pkg.
+	//
+	// (previously, pkg.goVersion was mutated here: go.dev/issue/61212)
 
 	return &Checker{
-		conf:    conf,
-		ctxt:    conf.Context,
-		pkg:     pkg,
-		Info:    info,
-		version: version,
-		objMap:  make(map[Object]*declInfo),
-		impMap:  make(map[importKey]*Package),
+		conf:   conf,
+		ctxt:   conf.Context,
+		pkg:    pkg,
+		Info:   info,
+		objMap: make(map[Object]*declInfo),
+		impMap: make(map[importKey]*Package),
 	}
 }
 
@@ -333,6 +334,20 @@
 var errBadCgo = errors.New("cannot use FakeImportC and go115UsesCgo together")
 
 func (check *Checker) checkFiles(files []*syntax.File) (err error) {
+	if check.pkg == Unsafe {
+		// Defensive handling for Unsafe, which cannot be type checked, and must
+		// not be mutated. See https://go.dev/issue/61212 for an example of where
+		// Unsafe is passed to NewChecker.
+		return nil
+	}
+
+	check.version, err = parseGoVersion(check.conf.GoVersion)
+	if err != nil {
+		return err
+	}
+	if check.version.after(version{1, goversion.Version}) {
+		return fmt.Errorf("package requires newer Go version %v", check.version)
+	}
 	if check.conf.FakeImportC && check.conf.go115UsesCgo {
 		return errBadCgo
 	}
@@ -377,6 +392,7 @@
 		check.monomorph()
 	}
 
+	check.pkg.goVersion = check.conf.GoVersion
 	check.pkg.complete = true
 
 	// no longer needed - release memory
diff --git a/src/cmd/compile/internal/types2/issues_test.go b/src/cmd/compile/internal/types2/issues_test.go
index 8bd42a5..5e0ae21 100644
--- a/src/cmd/compile/internal/types2/issues_test.go
+++ b/src/cmd/compile/internal/types2/issues_test.go
@@ -497,14 +497,14 @@
 	//                 _ T2
 	//         }
 	// }
-	n1 := NewTypeName(syntax.Pos{}, nil, "T1", nil)
+	n1 := NewTypeName(nopos, nil, "T1", nil)
 	T1 := NewNamed(n1, nil, nil)
-	n2 := NewTypeName(syntax.Pos{}, nil, "T2", nil)
+	n2 := NewTypeName(nopos, nil, "T2", nil)
 	T2 := NewNamed(n2, nil, nil)
-	s1 := NewStruct([]*Var{NewField(syntax.Pos{}, nil, "_", T2, false)}, nil)
+	s1 := NewStruct([]*Var{NewField(nopos, nil, "_", T2, false)}, nil)
 	T1.SetUnderlying(s1)
-	s2 := NewStruct([]*Var{NewField(syntax.Pos{}, nil, "_", T2, false)}, nil)
-	s3 := NewStruct([]*Var{NewField(syntax.Pos{}, nil, "_", s2, false)}, nil)
+	s2 := NewStruct([]*Var{NewField(nopos, nil, "_", T2, false)}, nil)
+	s3 := NewStruct([]*Var{NewField(nopos, nil, "_", s2, false)}, nil)
 	T2.SetUnderlying(s3)
 
 	// These calls must terminate (no endless recursion).
@@ -535,38 +535,69 @@
 }
 
 func TestIssue43124(t *testing.T) {
-	testenv.MustHaveGoBuild(t)
+	// TODO(rFindley) move this to testdata by enhancing support for importing.
+
+	testenv.MustHaveGoBuild(t) // The go command is needed for the importer to determine the locations of stdlib .a files.
 
 	// All involved packages have the same name (template). Error messages should
 	// disambiguate between text/template and html/template by printing the full
 	// path.
 	const (
 		asrc = `package a; import "text/template"; func F(template.Template) {}; func G(int) {}`
-		bsrc = `package b; import ("a"; "html/template"); func _() { a.F(template.Template{}) }`
-		csrc = `package c; import ("a"; "html/template"); func _() { a.G(template.Template{}) }`
+		bsrc = `
+package b
+
+import (
+	"a"
+	"html/template"
+)
+
+func _() {
+	// Packages should be fully qualified when there is ambiguity within the
+	// error string itself.
+	a.F(template /* ERRORx "cannot use.*html/template.* as .*text/template" */ .Template{})
+}
+`
+		csrc = `
+package c
+
+import (
+	"a"
+	"fmt"
+	"html/template"
+)
+
+// go.dev/issue/46905: make sure template is not the first package qualified.
+var _ fmt.Stringer = 1 // ERRORx "cannot use 1.*as fmt\\.Stringer"
+
+// Packages should be fully qualified when there is ambiguity in reachable
+// packages. In this case both a (and for that matter html/template) import
+// text/template.
+func _() { a.G(template /* ERRORx "cannot use .*html/template.*Template" */ .Template{}) }
+`
+
+		tsrc = `
+package template
+
+import "text/template"
+
+type T int
+
+// Verify that the current package name also causes disambiguation.
+var _ T = template /* ERRORx "cannot use.*text/template.* as T value" */.Template{}
+`
 	)
 
 	a := mustTypecheck(asrc, nil, nil)
-	conf := Config{Importer: importHelper{pkg: a, fallback: defaultImporter()}}
+	imp := importHelper{pkg: a, fallback: defaultImporter()}
 
-	// Packages should be fully qualified when there is ambiguity within the
-	// error string itself.
-	_, err := typecheck(bsrc, &conf, nil)
-	if err == nil {
-		t.Fatal("package b had no errors")
-	}
-	if !strings.Contains(err.Error(), "text/template") || !strings.Contains(err.Error(), "html/template") {
-		t.Errorf("type checking error for b does not disambiguate package template: %q", err)
+	withImporter := func(cfg *Config) {
+		cfg.Importer = imp
 	}
 
-	// ...and also when there is any ambiguity in reachable packages.
-	_, err = typecheck(csrc, &conf, nil)
-	if err == nil {
-		t.Fatal("package c had no errors")
-	}
-	if !strings.Contains(err.Error(), "html/template") {
-		t.Errorf("type checking error for c does not disambiguate package template: %q", err)
-	}
+	testFiles(t, []string{"b.go"}, [][]byte{[]byte(bsrc)}, 0, false, withImporter)
+	testFiles(t, []string{"c.go"}, [][]byte{[]byte(csrc)}, 0, false, withImporter)
+	testFiles(t, []string{"t.go"}, [][]byte{[]byte(tsrc)}, 0, false, withImporter)
 }
 
 func TestIssue50646(t *testing.T) {
diff --git a/src/cmd/compile/internal/types2/package.go b/src/cmd/compile/internal/types2/package.go
index 61670f6..e08099d 100644
--- a/src/cmd/compile/internal/types2/package.go
+++ b/src/cmd/compile/internal/types2/package.go
@@ -10,13 +10,14 @@
 
 // A Package describes a Go package.
 type Package struct {
-	path     string
-	name     string
-	scope    *Scope
-	imports  []*Package
-	complete bool
-	fake     bool // scope lookup errors are silently dropped if package is fake (internal use only)
-	cgo      bool // uses of this package will be rewritten into uses of declarations from _cgo_gotypes.go
+	path      string
+	name      string
+	scope     *Scope
+	imports   []*Package
+	complete  bool
+	fake      bool   // scope lookup errors are silently dropped if package is fake (internal use only)
+	cgo       bool   // uses of this package will be rewritten into uses of declarations from _cgo_gotypes.go
+	goVersion string // minimum Go version required for package (by Config.GoVersion, typically from go.mod)
 }
 
 // NewPackage returns a new Package for the given package path and name.
@@ -35,6 +36,12 @@
 // SetName sets the package name.
 func (pkg *Package) SetName(name string) { pkg.name = name }
 
+// GoVersion returns the minimum Go version required by this package.
+// If the minimum version is unknown, GoVersion returns the empty string.
+// Individual source files may specify a different minimum Go version,
+// as reported in the [go/ast.File.GoVersion] field.
+func (pkg *Package) GoVersion() string { return pkg.goVersion }
+
 // Scope returns the (complete or incomplete) package scope
 // holding the objects declared at package level (TypeNames,
 // Consts, Vars, and Funcs).
diff --git a/src/cmd/compile/internal/types2/sizeof_test.go b/src/cmd/compile/internal/types2/sizeof_test.go
index af82b3f..740dbc9 100644
--- a/src/cmd/compile/internal/types2/sizeof_test.go
+++ b/src/cmd/compile/internal/types2/sizeof_test.go
@@ -47,7 +47,7 @@
 
 		// Misc
 		{Scope{}, 60, 104},
-		{Package{}, 36, 72},
+		{Package{}, 44, 88},
 		{_TypeSet{}, 28, 56},
 	}
 
diff --git a/src/cmd/compile/internal/types2/version.go b/src/cmd/compile/internal/types2/version.go
index 7d01b82..e525f16 100644
--- a/src/cmd/compile/internal/types2/version.go
+++ b/src/cmd/compile/internal/types2/version.go
@@ -6,7 +6,6 @@
 
 import (
 	"cmd/compile/internal/syntax"
-	"errors"
 	"fmt"
 	"strings"
 )
@@ -44,23 +43,24 @@
 	go1_21 = version{1, 21}
 )
 
-var errVersionSyntax = errors.New("invalid Go version syntax")
-
 // parseGoVersion parses a Go version string (such as "go1.12")
 // and returns the version, or an error. If s is the empty
 // string, the version is 0.0.
 func parseGoVersion(s string) (v version, err error) {
+	bad := func() (version, error) {
+		return version{}, fmt.Errorf("invalid Go version syntax %q", s)
+	}
 	if s == "" {
 		return
 	}
 	if !strings.HasPrefix(s, "go") {
-		return version{}, errVersionSyntax
+		return bad()
 	}
 	s = s[len("go"):]
 	i := 0
 	for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
 		if i >= 10 || i == 0 && s[i] == '0' {
-			return version{}, errVersionSyntax
+			return bad()
 		}
 		v.major = 10*v.major + int(s[i]) - '0'
 	}
@@ -68,7 +68,7 @@
 		return
 	}
 	if i == 0 || s[i] != '.' {
-		return version{}, errVersionSyntax
+		return bad()
 	}
 	s = s[i+1:]
 	if s == "0" {
@@ -81,14 +81,15 @@
 	i = 0
 	for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
 		if i >= 10 || i == 0 && s[i] == '0' {
-			return version{}, errVersionSyntax
+			return bad()
 		}
 		v.minor = 10*v.minor + int(s[i]) - '0'
 	}
-	if i > 0 && i == len(s) {
-		return
-	}
-	return version{}, errVersionSyntax
+	// Accept any suffix after the minor number.
+	// We are only looking for the language version (major.minor)
+	// but want to accept any valid Go version, like go1.21.0
+	// and go1.21rc2.
+	return
 }
 
 // langCompat reports an error if the representation of a numeric
diff --git a/src/cmd/compile/internal/types2/version_test.go b/src/cmd/compile/internal/types2/version_test.go
new file mode 100644
index 0000000..651758e
--- /dev/null
+++ b/src/cmd/compile/internal/types2/version_test.go
@@ -0,0 +1,24 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types2
+
+import "testing"
+
+var parseGoVersionTests = []struct {
+	in  string
+	out version
+}{
+	{"go1.21", version{1, 21}},
+	{"go1.21.0", version{1, 21}},
+	{"go1.21rc2", version{1, 21}},
+}
+
+func TestParseGoVersion(t *testing.T) {
+	for _, tt := range parseGoVersionTests {
+		if out, err := parseGoVersion(tt.in); out != tt.out || err != nil {
+			t.Errorf("parseGoVersion(%q) = %v, %v, want %v, nil", tt.in, out, err, tt.out)
+		}
+	}
+}
diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go
index d38a051..13d2a78 100644
--- a/src/cmd/go/internal/work/exec.go
+++ b/src/cmd/go/internal/work/exec.go
@@ -1115,6 +1115,7 @@
 	PackageVetx map[string]string // map package path to vetx data from earlier vet run
 	VetxOnly    bool              // only compute vetx data; don't report detected problems
 	VetxOutput  string            // write vetx data to this output file
+	GoVersion   string            // Go version for package
 
 	SucceedOnTypecheckFailure bool // awful hack; see #18395 and below
 }
@@ -1149,6 +1150,13 @@
 		PackageFile:  make(map[string]string),
 		Standard:     make(map[string]bool),
 	}
+	if a.Package.Module != nil {
+		v := a.Package.Module.GoVersion
+		if v == "" {
+			v = gover.DefaultGoModVersion
+		}
+		vcfg.GoVersion = "go" + v
+	}
 	a.vetCfg = vcfg
 	for i, raw := range a.Package.Internal.RawImports {
 		final := a.Package.Imports[i]
diff --git a/src/cmd/go/internal/work/gc.go b/src/cmd/go/internal/work/gc.go
index 6043ad5..26b4e0f 100644
--- a/src/cmd/go/internal/work/gc.go
+++ b/src/cmd/go/internal/work/gc.go
@@ -85,19 +85,7 @@
 	if p.Module != nil {
 		v := p.Module.GoVersion
 		if v == "" {
-			// We started adding a 'go' directive to the go.mod file unconditionally
-			// as of Go 1.12, so any module that still lacks such a directive must
-			// either have been authored before then, or have a hand-edited go.mod
-			// file that hasn't been updated by cmd/go since that edit.
-			//
-			// Unfortunately, through at least Go 1.16 we didn't add versions to
-			// vendor/modules.txt. So this could also be a vendored 1.16 dependency.
-			//
-			// Fortunately, there were no breaking changes to the language between Go
-			// 1.11 and 1.16, so if we assume Go 1.16 semantics we will not introduce
-			// any spurious errors — we will only mask errors, and not particularly
-			// important ones at that.
-			v = "1.16"
+			v = gover.DefaultGoModVersion
 		}
 		if allowedVersion(v) {
 			defaultGcFlags = append(defaultGcFlags, "-lang=go"+gover.Lang(v))
diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go
index a77d63d..836fe83 100644
--- a/src/database/sql/sql.go
+++ b/src/database/sql/sql.go
@@ -2944,15 +2944,17 @@
 	if bypassRowsAwaitDone {
 		return
 	}
-	ctx, rs.cancel = context.WithCancel(ctx)
-	go rs.awaitDone(ctx, txctx)
+	closectx, cancel := context.WithCancel(ctx)
+	rs.cancel = cancel
+	go rs.awaitDone(ctx, txctx, closectx)
 }
 
-// awaitDone blocks until either ctx or txctx is canceled. The ctx is provided
-// from the query context and is canceled when the query Rows is closed.
+// awaitDone blocks until ctx, txctx, or closectx is canceled.
+// The ctx is provided from the query context.
 // If the query was issued in a transaction, the transaction's context
-// is also provided in txctx to ensure Rows is closed if the Tx is closed.
-func (rs *Rows) awaitDone(ctx, txctx context.Context) {
+// is also provided in txctx, to ensure Rows is closed if the Tx is closed.
+// The closectx is closed by an explicit call to rs.Close.
+func (rs *Rows) awaitDone(ctx, txctx, closectx context.Context) {
 	var txctxDone <-chan struct{}
 	if txctx != nil {
 		txctxDone = txctx.Done()
@@ -2964,6 +2966,9 @@
 	case <-txctxDone:
 		err := txctx.Err()
 		rs.contextDone.Store(&err)
+	case <-closectx.Done():
+		// rs.cancel was called via Close(); don't store this into contextDone
+		// to ensure Err() is unaffected.
 	}
 	rs.close(ctx.Err())
 }
diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go
index 718056c..e6a5cd9 100644
--- a/src/database/sql/sql_test.go
+++ b/src/database/sql/sql_test.go
@@ -4493,6 +4493,31 @@
 	}
 }
 
+func TestNilErrorAfterClose(t *testing.T) {
+	db := newTestDB(t, "people")
+	defer closeDB(t, db)
+
+	// This WithCancel is important; Rows contains an optimization to avoid
+	// spawning a goroutine when the query/transaction context cannot be
+	// canceled, but this test tests a bug which is caused by said goroutine.
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+
+	r, err := db.QueryContext(ctx, "SELECT|people|name|")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if err := r.Close(); err != nil {
+		t.Fatal(err)
+	}
+
+	time.Sleep(10 * time.Millisecond) // increase odds of seeing failure
+	if err := r.Err(); err != nil {
+		t.Fatal(err)
+	}
+}
+
 // badConn implements a bad driver.Conn, for TestBadDriver.
 // The Exec method panics.
 type badConn struct{}
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index be8ac30..2f33506 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -286,7 +286,7 @@
 	math/big, go/token
 	< go/constant;
 
-	container/heap, go/constant, go/parser, internal/types/errors
+	container/heap, go/constant, go/parser, internal/goversion, internal/types/errors
 	< go/types;
 
 	# The vast majority of standard library packages should not be resorting to regexp.
diff --git a/src/go/types/check.go b/src/go/types/check.go
index 5381b5d..3b0f5e4 100644
--- a/src/go/types/check.go
+++ b/src/go/types/check.go
@@ -12,6 +12,7 @@
 	"go/ast"
 	"go/constant"
 	"go/token"
+	"internal/goversion"
 	. "internal/types/errors"
 )
 
@@ -233,20 +234,20 @@
 		info = new(Info)
 	}
 
-	version, err := parseGoVersion(conf.GoVersion)
-	if err != nil {
-		panic(fmt.Sprintf("invalid Go version %q (%v)", conf.GoVersion, err))
-	}
+	// Note: clients may call NewChecker with the Unsafe package, which is
+	// globally shared and must not be mutated. Therefore NewChecker must not
+	// mutate *pkg.
+	//
+	// (previously, pkg.goVersion was mutated here: go.dev/issue/61212)
 
 	return &Checker{
-		conf:    conf,
-		ctxt:    conf.Context,
-		fset:    fset,
-		pkg:     pkg,
-		Info:    info,
-		version: version,
-		objMap:  make(map[Object]*declInfo),
-		impMap:  make(map[importKey]*Package),
+		conf:   conf,
+		ctxt:   conf.Context,
+		fset:   fset,
+		pkg:    pkg,
+		Info:   info,
+		objMap: make(map[Object]*declInfo),
+		impMap: make(map[importKey]*Package),
 	}
 }
 
@@ -342,6 +343,20 @@
 var errBadCgo = errors.New("cannot use FakeImportC and go115UsesCgo together")
 
 func (check *Checker) checkFiles(files []*ast.File) (err error) {
+	if check.pkg == Unsafe {
+		// Defensive handling for Unsafe, which cannot be type checked, and must
+		// not be mutated. See https://go.dev/issue/61212 for an example of where
+		// Unsafe is passed to NewChecker.
+		return nil
+	}
+
+	check.version, err = parseGoVersion(check.conf.GoVersion)
+	if err != nil {
+		return err
+	}
+	if check.version.after(version{1, goversion.Version}) {
+		return fmt.Errorf("package requires newer Go version %v", check.version)
+	}
 	if check.conf.FakeImportC && check.conf.go115UsesCgo {
 		return errBadCgo
 	}
@@ -386,6 +401,7 @@
 		check.monomorph()
 	}
 
+	check.pkg.goVersion = check.conf.GoVersion
 	check.pkg.complete = true
 
 	// no longer needed - release memory
diff --git a/src/go/types/generate_test.go b/src/go/types/generate_test.go
index 05a848b..75fda02 100644
--- a/src/go/types/generate_test.go
+++ b/src/go/types/generate_test.go
@@ -141,6 +141,7 @@
 	"universe.go":      fixGlobalTypVarDecl,
 	"util_test.go":     fixTokenPos,
 	"validtype.go":     nil,
+	"version_test.go":  nil,
 }
 
 // TODO(gri) We should be able to make these rewriters more configurable/composable.
diff --git a/src/go/types/package.go b/src/go/types/package.go
index 7aa62fb..0f52d5f 100644
--- a/src/go/types/package.go
+++ b/src/go/types/package.go
@@ -12,13 +12,14 @@
 
 // A Package describes a Go package.
 type Package struct {
-	path     string
-	name     string
-	scope    *Scope
-	imports  []*Package
-	complete bool
-	fake     bool // scope lookup errors are silently dropped if package is fake (internal use only)
-	cgo      bool // uses of this package will be rewritten into uses of declarations from _cgo_gotypes.go
+	path      string
+	name      string
+	scope     *Scope
+	imports   []*Package
+	complete  bool
+	fake      bool   // scope lookup errors are silently dropped if package is fake (internal use only)
+	cgo       bool   // uses of this package will be rewritten into uses of declarations from _cgo_gotypes.go
+	goVersion string // minimum Go version required for package (by Config.GoVersion, typically from go.mod)
 }
 
 // NewPackage returns a new Package for the given package path and name.
@@ -37,6 +38,12 @@
 // SetName sets the package name.
 func (pkg *Package) SetName(name string) { pkg.name = name }
 
+// GoVersion returns the minimum Go version required by this package.
+// If the minimum version is unknown, GoVersion returns the empty string.
+// Individual source files may specify a different minimum Go version,
+// as reported in the [go/ast.File.GoVersion] field.
+func (pkg *Package) GoVersion() string { return pkg.goVersion }
+
 // Scope returns the (complete or incomplete) package scope
 // holding the objects declared at package level (TypeNames,
 // Consts, Vars, and Funcs).
diff --git a/src/go/types/sizeof_test.go b/src/go/types/sizeof_test.go
index f17a178..9e5b5f8 100644
--- a/src/go/types/sizeof_test.go
+++ b/src/go/types/sizeof_test.go
@@ -46,7 +46,7 @@
 
 		// Misc
 		{Scope{}, 44, 88},
-		{Package{}, 36, 72},
+		{Package{}, 44, 88},
 		{_TypeSet{}, 28, 56},
 	}
 	for _, test := range tests {
diff --git a/src/go/types/version.go b/src/go/types/version.go
index 07a42a7..108d9b3 100644
--- a/src/go/types/version.go
+++ b/src/go/types/version.go
@@ -5,7 +5,6 @@
 package types
 
 import (
-	"errors"
 	"fmt"
 	"go/ast"
 	"go/token"
@@ -45,23 +44,24 @@
 	go1_21 = version{1, 21}
 )
 
-var errVersionSyntax = errors.New("invalid Go version syntax")
-
 // parseGoVersion parses a Go version string (such as "go1.12")
 // and returns the version, or an error. If s is the empty
 // string, the version is 0.0.
 func parseGoVersion(s string) (v version, err error) {
+	bad := func() (version, error) {
+		return version{}, fmt.Errorf("invalid Go version syntax %q", s)
+	}
 	if s == "" {
 		return
 	}
 	if !strings.HasPrefix(s, "go") {
-		return version{}, errVersionSyntax
+		return bad()
 	}
 	s = s[len("go"):]
 	i := 0
 	for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
 		if i >= 10 || i == 0 && s[i] == '0' {
-			return version{}, errVersionSyntax
+			return bad()
 		}
 		v.major = 10*v.major + int(s[i]) - '0'
 	}
@@ -69,7 +69,7 @@
 		return
 	}
 	if i == 0 || s[i] != '.' {
-		return version{}, errVersionSyntax
+		return bad()
 	}
 	s = s[i+1:]
 	if s == "0" {
@@ -82,14 +82,15 @@
 	i = 0
 	for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
 		if i >= 10 || i == 0 && s[i] == '0' {
-			return version{}, errVersionSyntax
+			return bad()
 		}
 		v.minor = 10*v.minor + int(s[i]) - '0'
 	}
-	if i > 0 && i == len(s) {
-		return
-	}
-	return version{}, errVersionSyntax
+	// Accept any suffix after the minor number.
+	// We are only looking for the language version (major.minor)
+	// but want to accept any valid Go version, like go1.21.0
+	// and go1.21rc2.
+	return
 }
 
 // langCompat reports an error if the representation of a numeric
diff --git a/src/go/types/version_test.go b/src/go/types/version_test.go
new file mode 100644
index 0000000..d25f7f5
--- /dev/null
+++ b/src/go/types/version_test.go
@@ -0,0 +1,26 @@
+// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT.
+
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types
+
+import "testing"
+
+var parseGoVersionTests = []struct {
+	in  string
+	out version
+}{
+	{"go1.21", version{1, 21}},
+	{"go1.21.0", version{1, 21}},
+	{"go1.21rc2", version{1, 21}},
+}
+
+func TestParseGoVersion(t *testing.T) {
+	for _, tt := range parseGoVersionTests {
+		if out, err := parseGoVersion(tt.in); out != tt.out || err != nil {
+			t.Errorf("parseGoVersion(%q) = %v, %v, want %v, nil", tt.in, out, err, tt.out)
+		}
+	}
+}
diff --git a/src/log/slog/handler.go b/src/log/slog/handler.go
index dc4c2d9..e479ca8 100644
--- a/src/log/slog/handler.go
+++ b/src/log/slog/handler.go
@@ -221,6 +221,11 @@
 }
 
 func (h *commonHandler) withAttrs(as []Attr) *commonHandler {
+	// We are going to ignore empty groups, so if the entire slice consists of
+	// them, there is nothing to do.
+	if countEmptyGroups(as) == len(as) {
+		return h
+	}
 	h2 := h.clone()
 	// Pre-format the attributes as an optimization.
 	state := h2.newHandleState((*buffer.Buffer)(&h2.preformattedAttrs), false, "")
@@ -308,15 +313,20 @@
 	}
 	// Attrs in Record -- unlike the built-in ones, they are in groups started
 	// from WithGroup.
-	s.prefix.WriteString(s.h.groupPrefix)
-	s.openGroups()
-	r.Attrs(func(a Attr) bool {
-		s.appendAttr(a)
-		return true
-	})
+	// If the record has no Attrs, don't output any groups.
+	nOpenGroups := s.h.nOpenGroups
+	if r.NumAttrs() > 0 {
+		s.prefix.WriteString(s.h.groupPrefix)
+		s.openGroups()
+		nOpenGroups = len(s.h.groups)
+		r.Attrs(func(a Attr) bool {
+			s.appendAttr(a)
+			return true
+		})
+	}
 	if s.h.json {
 		// Close all open groups.
-		for range s.h.groups {
+		for range s.h.groups[:nOpenGroups] {
 			s.buf.WriteByte('}')
 		}
 		// Close the top-level object.
diff --git a/src/log/slog/handler_test.go b/src/log/slog/handler_test.go
index 741e86a..f43d841 100644
--- a/src/log/slog/handler_test.go
+++ b/src/log/slog/handler_test.go
@@ -215,6 +215,28 @@
 			wantJSON: `{"msg":"message","h":{"a":1}}`,
 		},
 		{
+			name:    "nested empty group",
+			replace: removeKeys(TimeKey, LevelKey),
+			attrs: []Attr{
+				Group("g",
+					Group("h",
+						Group("i"), Group("j"))),
+			},
+			wantText: `msg=message`,
+			wantJSON: `{"msg":"message"}`,
+		},
+		{
+			name:    "nested non-empty group",
+			replace: removeKeys(TimeKey, LevelKey),
+			attrs: []Attr{
+				Group("g",
+					Group("h",
+						Group("i"), Group("j", Int("a", 1)))),
+			},
+			wantText: `msg=message g.h.j.a=1`,
+			wantJSON: `{"msg":"message","g":{"h":{"j":{"a":1}}}}`,
+		},
+		{
 			name:    "escapes",
 			replace: removeKeys(TimeKey, LevelKey),
 			attrs: []Attr{
@@ -282,6 +304,34 @@
 			wantJSON: `{"msg":"message","p1":1,"s1":{"s2":{"a":"one","b":2}}}`,
 		},
 		{
+			name:    "empty with-groups",
+			replace: removeKeys(TimeKey, LevelKey),
+			with: func(h Handler) Handler {
+				return h.WithGroup("x").WithGroup("y")
+			},
+			wantText: "msg=message",
+			wantJSON: `{"msg":"message"}`,
+		},
+		{
+			name:    "empty with-groups, no non-empty attrs",
+			replace: removeKeys(TimeKey, LevelKey),
+			with: func(h Handler) Handler {
+				return h.WithGroup("x").WithAttrs([]Attr{Group("g")}).WithGroup("y")
+			},
+			wantText: "msg=message",
+			wantJSON: `{"msg":"message"}`,
+		},
+		{
+			name:    "one empty with-group",
+			replace: removeKeys(TimeKey, LevelKey),
+			with: func(h Handler) Handler {
+				return h.WithGroup("x").WithAttrs([]Attr{Int("a", 1)}).WithGroup("y")
+			},
+			attrs:    []Attr{Group("g", Group("h"))},
+			wantText: "msg=message x.a=1",
+			wantJSON: `{"msg":"message","x":{"a":1}}`,
+		},
+		{
 			name:     "GroupValue as Attr value",
 			replace:  removeKeys(TimeKey, LevelKey),
 			attrs:    []Attr{{"v", AnyValue(IntValue(3))}},
diff --git a/src/log/slog/logger_test.go b/src/log/slog/logger_test.go
index d151c04..130f2e6 100644
--- a/src/log/slog/logger_test.go
+++ b/src/log/slog/logger_test.go
@@ -106,7 +106,7 @@
 	// log.Logger's output goes through the handler.
 	SetDefault(New(NewTextHandler(&slogbuf, &HandlerOptions{AddSource: true})))
 	log.Print("msg2")
-	checkLogOutput(t, slogbuf.String(), "time="+timeRE+` level=INFO source=.*logger_test.go:\d{3} msg=msg2`)
+	checkLogOutput(t, slogbuf.String(), "time="+timeRE+` level=INFO source=.*logger_test.go:\d{3}"? msg=msg2`)
 
 	// The default log.Logger always outputs at Info level.
 	slogbuf.Reset()
diff --git a/src/log/slog/record.go b/src/log/slog/record.go
index 972552d..67b76f3 100644
--- a/src/log/slog/record.go
+++ b/src/log/slog/record.go
@@ -93,9 +93,17 @@
 }
 
 // AddAttrs appends the given Attrs to the Record's list of Attrs.
+// It omits empty groups.
 func (r *Record) AddAttrs(attrs ...Attr) {
-	n := copy(r.front[r.nFront:], attrs)
-	r.nFront += n
+	var i int
+	for i = 0; i < len(attrs) && r.nFront < len(r.front); i++ {
+		a := attrs[i]
+		if a.Value.isEmptyGroup() {
+			continue
+		}
+		r.front[r.nFront] = a
+		r.nFront++
+	}
 	// Check if a copy was modified by slicing past the end
 	// and seeing if the Attr there is non-zero.
 	if cap(r.back) > len(r.back) {
@@ -104,15 +112,25 @@
 			panic("copies of a slog.Record were both modified")
 		}
 	}
-	r.back = append(r.back, attrs[n:]...)
+	ne := countEmptyGroups(attrs[i:])
+	r.back = slices.Grow(r.back, len(attrs[i:])-ne)
+	for _, a := range attrs[i:] {
+		if !a.Value.isEmptyGroup() {
+			r.back = append(r.back, a)
+		}
+	}
 }
 
 // Add converts the args to Attrs as described in [Logger.Log],
 // then appends the Attrs to the Record's list of Attrs.
+// It omits empty groups.
 func (r *Record) Add(args ...any) {
 	var a Attr
 	for len(args) > 0 {
 		a, args = argsToAttr(args)
+		if a.Value.isEmptyGroup() {
+			continue
+		}
 		if r.nFront < len(r.front) {
 			r.front[r.nFront] = a
 			r.nFront++
diff --git a/src/log/slog/value.go b/src/log/slog/value.go
index 71a59d2..224848f 100644
--- a/src/log/slog/value.go
+++ b/src/log/slog/value.go
@@ -164,9 +164,32 @@
 // GroupValue returns a new Value for a list of Attrs.
 // The caller must not subsequently mutate the argument slice.
 func GroupValue(as ...Attr) Value {
+	// Remove empty groups.
+	// It is simpler overall to do this at construction than
+	// to check each Group recursively for emptiness.
+	if n := countEmptyGroups(as); n > 0 {
+		as2 := make([]Attr, 0, len(as)-n)
+		for _, a := range as {
+			if !a.Value.isEmptyGroup() {
+				as2 = append(as2, a)
+			}
+		}
+		as = as2
+	}
 	return Value{num: uint64(len(as)), any: groupptr(unsafe.SliceData(as))}
 }
 
+// countEmptyGroups returns the number of empty group values in its argument.
+func countEmptyGroups(as []Attr) int {
+	n := 0
+	for _, a := range as {
+		if a.Value.isEmptyGroup() {
+			n++
+		}
+	}
+	return n
+}
+
 // AnyValue returns a Value for the supplied value.
 //
 // If the supplied value is of type Value, it is returned
@@ -399,6 +422,17 @@
 	}
 }
 
+// isEmptyGroup reports whether v is a group that has no attributes.
+func (v Value) isEmptyGroup() bool {
+	if v.Kind() != KindGroup {
+		return false
+	}
+	// We do not need to recursively examine the group's Attrs for emptiness,
+	// because GroupValue removed them when the group was constructed, and
+	// groups are immutable.
+	return len(v.group()) == 0
+}
+
 // append appends a text representation of v to dst.
 // v is formatted as with fmt.Sprint.
 func (v Value) append(dst []byte) []byte {
diff --git a/src/log/slog/value_test.go b/src/log/slog/value_test.go
index 615bed7..923a4e0 100644
--- a/src/log/slog/value_test.go
+++ b/src/log/slog/value_test.go
@@ -229,6 +229,18 @@
 	}
 }
 
+func TestEmptyGroup(t *testing.T) {
+	g := GroupValue(
+		Int("a", 1),
+		Group("g1", Group("g2")),
+		Group("g3", Group("g4", Int("b", 2))))
+	got := g.Group()
+	want := []Attr{Int("a", 1), Group("g3", Group("g4", Int("b", 2)))}
+	if !attrsEqual(got, want) {
+		t.Errorf("\ngot  %v\nwant %v", got, want)
+	}
+}
+
 type replace struct {
 	v Value
 }
diff --git a/src/math/all_test.go b/src/math/all_test.go
index 886267b..af3c38c 100644
--- a/src/math/all_test.go
+++ b/src/math/all_test.go
@@ -2059,6 +2059,9 @@
 
 	// Special
 	{0, 0, 0, 0},
+	{Copysign(0, -1), 0, 0, 0},
+	{0, 0, Copysign(0, -1), 0},
+	{Copysign(0, -1), 0, Copysign(0, -1), Copysign(0, -1)},
 	{-1.1754226043408471e-38, NaN(), Inf(0), NaN()},
 	{0, 0, 2.22507385643494e-308, 2.22507385643494e-308},
 	{-8.65697792e+09, NaN(), -7.516192799999999e+09, NaN()},
@@ -2077,6 +2080,10 @@
 	{4.612811918325842e+18, 1.4901161193847641e-08, 2.6077032311277997e-08, 6.873625395187494e+10},
 	{-9.094947033611148e-13, 4.450691014249257e-308, 2.086006742350485e-308, 2.086006742346437e-308},
 	{-7.751454006381804e-05, 5.588653777189071e-308, -2.2207280111272877e-308, -2.2211612130544025e-308},
+
+	// Issue #61130
+	{-1, 1, 1, 0},
+	{1, 1, -1, 0},
 }
 
 var sqrt32 = []float32{
@@ -3099,6 +3106,45 @@
 	}
 }
 
+//go:noinline
+func fmsub(x, y, z float64) float64 {
+	return FMA(x, y, -z)
+}
+
+//go:noinline
+func fnmsub(x, y, z float64) float64 {
+	return FMA(-x, y, z)
+}
+
+//go:noinline
+func fnmadd(x, y, z float64) float64 {
+	return FMA(-x, y, -z)
+}
+
+func TestFMANegativeArgs(t *testing.T) {
+	// Some architectures have instructions for fused multiply-subtract and
+	// also negated variants of fused multiply-add and subtract. This test
+	// aims to check that the optimizations that generate those instructions
+	// are applied correctly, if they exist.
+	for _, c := range fmaC {
+		want := PortableFMA(c.x, c.y, -c.z)
+		got := fmsub(c.x, c.y, c.z)
+		if !alike(got, want) {
+			t.Errorf("FMA(%g, %g, -(%g)) == %g, want %g", c.x, c.y, c.z, got, want)
+		}
+		want = PortableFMA(-c.x, c.y, c.z)
+		got = fnmsub(c.x, c.y, c.z)
+		if !alike(got, want) {
+			t.Errorf("FMA(-(%g), %g, %g) == %g, want %g", c.x, c.y, c.z, got, want)
+		}
+		want = PortableFMA(-c.x, c.y, -c.z)
+		got = fnmadd(c.x, c.y, c.z)
+		if !alike(got, want) {
+			t.Errorf("FMA(-(%g), %g, -(%g)) == %g, want %g", c.x, c.y, c.z, got, want)
+		}
+	}
+}
+
 // Check that math functions of high angle values
 // return accurate results. [Since (vf[i] + large) - large != vf[i],
 // testing for Trig(vf[i] + large) == Trig(vf[i]), where large is
diff --git a/src/math/fma.go b/src/math/fma.go
index ca0bf99..ba03fbe 100644
--- a/src/math/fma.go
+++ b/src/math/fma.go
@@ -132,6 +132,11 @@
 		ps, pe, pm1, pm2, zs, ze, zm1, zm2 = zs, ze, zm1, zm2, ps, pe, pm1, pm2
 	}
 
+	// Special case: if p == -z the result is always +0 since neither operand is zero.
+	if ps != zs && pe == ze && pm1 == zm1 && pm2 == zm2 {
+		return 0
+	}
+
 	// Align significands
 	zm1, zm2 = shrcompress(zm1, zm2, uint(pe-ze))
 
diff --git a/src/net/cgo_stub.go b/src/net/cgo_stub.go
index bd48311..b26b11a 100644
--- a/src/net/cgo_stub.go
+++ b/src/net/cgo_stub.go
@@ -3,12 +3,13 @@
 // license that can be found in the LICENSE file.
 
 // This file holds stub versions of the cgo functions called on Unix systems.
-// We build this file if using the netgo build tag, or if cgo is not
-// enabled and we are using a Unix system other than Darwin.
-// Darwin is exempted because it always provides the cgo routines,
-// in cgo_unix_syscall.go.
+// We build this file:
+// - if using the netgo build tag on a Unix system
+// - on a Unix system without the cgo resolver functions
+//   (Darwin always provides the cgo functions, in cgo_unix_syscall.go)
+// - on wasip1, where cgo is never available
 
-//go:build netgo || (!cgo && unix && !darwin)
+//go:build (netgo && unix) || (unix && !cgo && !darwin) || wasip1
 
 package net
 
diff --git a/src/net/conf.go b/src/net/conf.go
index 1db166c..77cc635 100644
--- a/src/net/conf.go
+++ b/src/net/conf.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.
 
-//go:build !js && !wasip1
+//go:build !js
 
 package net
 
diff --git a/src/net/dnsclient_unix.go b/src/net/dnsclient_unix.go
index f3c075c..dab5144 100644
--- a/src/net/dnsclient_unix.go
+++ b/src/net/dnsclient_unix.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.
 
-//go:build !js && !wasip1
+//go:build !js
 
 // DNS client: see RFC 1035.
 // Has to be linked into package net for Dial.
diff --git a/src/net/dnsconfig_unix.go b/src/net/dnsconfig_unix.go
index d5f34e5..69b3004 100644
--- a/src/net/dnsconfig_unix.go
+++ b/src/net/dnsconfig_unix.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.
 
-//go:build !js && !wasip1 && !windows
+//go:build !js && !windows
 
 // Read system DNS config from /etc/resolv.conf
 
diff --git a/src/net/http/http_test.go b/src/net/http/http_test.go
index 1c9fb33..91bb1b2 100644
--- a/src/net/http/http_test.go
+++ b/src/net/http/http_test.go
@@ -48,35 +48,6 @@
 	}
 }
 
-func TestCleanHost(t *testing.T) {
-	tests := []struct {
-		in, want string
-	}{
-		{"www.google.com", "www.google.com"},
-		{"www.google.com foo", "www.google.com"},
-		{"www.google.com/foo", "www.google.com"},
-		{" first character is a space", ""},
-		{"[1::6]:8080", "[1::6]:8080"},
-
-		// Punycode:
-		{"гофер.рф/foo", "xn--c1ae0ajs.xn--p1ai"},
-		{"bücher.de", "xn--bcher-kva.de"},
-		{"bücher.de:8080", "xn--bcher-kva.de:8080"},
-		// Verify we convert to lowercase before punycode:
-		{"BÜCHER.de", "xn--bcher-kva.de"},
-		{"BÜCHER.de:8080", "xn--bcher-kva.de:8080"},
-		// Verify we normalize to NFC before punycode:
-		{"gophér.nfc", "xn--gophr-esa.nfc"},            // NFC input; no work needed
-		{"goph\u0065\u0301r.nfd", "xn--gophr-esa.nfd"}, // NFD input
-	}
-	for _, tt := range tests {
-		got := cleanHost(tt.in)
-		if tt.want != got {
-			t.Errorf("cleanHost(%q) = %q, want %q", tt.in, got, tt.want)
-		}
-	}
-}
-
 // Test that cmd/go doesn't link in the HTTP server.
 //
 // This catches accidental dependencies between the HTTP transport and
diff --git a/src/net/http/request.go b/src/net/http/request.go
index 4e91904..bd86837 100644
--- a/src/net/http/request.go
+++ b/src/net/http/request.go
@@ -17,7 +17,6 @@
 	"io"
 	"mime"
 	"mime/multipart"
-	"net"
 	"net/http/httptrace"
 	"net/http/internal/ascii"
 	"net/textproto"
@@ -27,6 +26,7 @@
 	"strings"
 	"sync"
 
+	"golang.org/x/net/http/httpguts"
 	"golang.org/x/net/idna"
 )
 
@@ -580,12 +580,19 @@
 	// is not given, use the host from the request URL.
 	//
 	// Clean the host, in case it arrives with unexpected stuff in it.
-	host := cleanHost(r.Host)
+	host := r.Host
 	if host == "" {
 		if r.URL == nil {
 			return errMissingHost
 		}
-		host = cleanHost(r.URL.Host)
+		host = r.URL.Host
+	}
+	host, err = httpguts.PunycodeHostPort(host)
+	if err != nil {
+		return err
+	}
+	if !httpguts.ValidHostHeader(host) {
+		return errors.New("http: invalid Host header")
 	}
 
 	// According to RFC 6874, an HTTP client, proxy, or other
@@ -742,40 +749,6 @@
 	return idna.Lookup.ToASCII(v)
 }
 
-// cleanHost cleans up the host sent in request's Host header.
-//
-// It both strips anything after '/' or ' ', and puts the value
-// into Punycode form, if necessary.
-//
-// Ideally we'd clean the Host header according to the spec:
-//
-//	https://tools.ietf.org/html/rfc7230#section-5.4 (Host = uri-host [ ":" port ]")
-//	https://tools.ietf.org/html/rfc7230#section-2.7 (uri-host -> rfc3986's host)
-//	https://tools.ietf.org/html/rfc3986#section-3.2.2 (definition of host)
-//
-// But practically, what we are trying to avoid is the situation in
-// issue 11206, where a malformed Host header used in the proxy context
-// would create a bad request. So it is enough to just truncate at the
-// first offending character.
-func cleanHost(in string) string {
-	if i := strings.IndexAny(in, " /"); i != -1 {
-		in = in[:i]
-	}
-	host, port, err := net.SplitHostPort(in)
-	if err != nil { // input was just a host
-		a, err := idnaASCII(in)
-		if err != nil {
-			return in // garbage in, garbage out
-		}
-		return a
-	}
-	a, err := idnaASCII(host)
-	if err != nil {
-		return in // garbage in, garbage out
-	}
-	return net.JoinHostPort(a, port)
-}
-
 // removeZone removes IPv6 zone identifier from host.
 // E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080"
 func removeZone(host string) string {
diff --git a/src/net/http/request_test.go b/src/net/http/request_test.go
index 78b968f..0892bc2 100644
--- a/src/net/http/request_test.go
+++ b/src/net/http/request_test.go
@@ -775,15 +775,8 @@
 	}
 	req.Host = "foo.com with spaces"
 	req.URL.Host = "foo.com with spaces"
-	req.Write(logWrites{t, &got})
-	want := []string{
-		"GET /after HTTP/1.1\r\n",
-		"Host: foo.com\r\n",
-		"User-Agent: " + DefaultUserAgent + "\r\n",
-		"\r\n",
-	}
-	if !reflect.DeepEqual(got, want) {
-		t.Errorf("Writes = %q\n  Want = %q", got, want)
+	if err := req.Write(logWrites{t, &got}); err == nil {
+		t.Errorf("Writing request with invalid Host: succeded, want error")
 	}
 }
 
diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go
index 172aba6..028fecc 100644
--- a/src/net/http/transport_test.go
+++ b/src/net/http/transport_test.go
@@ -6731,3 +6731,22 @@
 	}
 	wg.Wait()
 }
+
+func TestRequestSanitization(t *testing.T) { run(t, testRequestSanitization) }
+func testRequestSanitization(t *testing.T, mode testMode) {
+	if mode == http2Mode {
+		// Remove this after updating x/net.
+		t.Skip("https://go.dev/issue/60374 test fails when run with HTTP/2")
+	}
+	ts := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, req *Request) {
+		if h, ok := req.Header["X-Evil"]; ok {
+			t.Errorf("request has X-Evil header: %q", h)
+		}
+	})).ts
+	req, _ := NewRequest("GET", ts.URL, nil)
+	req.Host = "go.dev\r\nX-Evil:evil"
+	resp, _ := ts.Client().Do(req)
+	if resp != nil {
+		resp.Body.Close()
+	}
+}
diff --git a/src/net/lookup_fake.go b/src/net/lookup_fake.go
index 45146e1..c27eae4 100644
--- a/src/net/lookup_fake.go
+++ b/src/net/lookup_fake.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.
 
-//go:build (js && wasm) || wasip1
+//go:build js && wasm
 
 package net
 
diff --git a/src/net/lookup_unix.go b/src/net/lookup_unix.go
index dc75e0a..56ae11e 100644
--- a/src/net/lookup_unix.go
+++ b/src/net/lookup_unix.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.
 
-//go:build unix
+//go:build unix || wasip1
 
 package net
 
diff --git a/src/net/net_fake.go b/src/net/net_fake.go
index 68d3696..908767a 100644
--- a/src/net/net_fake.go
+++ b/src/net/net_fake.go
@@ -15,8 +15,6 @@
 	"sync"
 	"syscall"
 	"time"
-
-	"golang.org/x/net/dns/dnsmessage"
 )
 
 var listenersMu sync.Mutex
@@ -406,7 +404,3 @@
 func (fd *fakeNetFD) dup() (f *os.File, err error) {
 	return nil, syscall.ENOSYS
 }
-
-func (r *Resolver) lookup(ctx context.Context, name string, qtype dnsmessage.Type, conf *dnsConfig) (dnsmessage.Parser, string, error) {
-	panic("unreachable")
-}
diff --git a/src/net/net_fake_js.go b/src/net/net_fake_js.go
index 1fc0b50..7ba108b6 100644
--- a/src/net/net_fake_js.go
+++ b/src/net/net_fake_js.go
@@ -8,7 +8,12 @@
 
 package net
 
-import "internal/poll"
+import (
+	"context"
+	"internal/poll"
+
+	"golang.org/x/net/dns/dnsmessage"
+)
 
 // Network file descriptor.
 type netFD struct {
@@ -25,3 +30,7 @@
 	pfd         poll.FD
 	isConnected bool // handshake completed or use of association with peer
 }
+
+func (r *Resolver) lookup(ctx context.Context, name string, qtype dnsmessage.Type, conf *dnsConfig) (dnsmessage.Parser, string, error) {
+	panic("unreachable")
+}
diff --git a/src/os/dir_darwin.go b/src/os/dir_darwin.go
index deba3eb..e6d5bda 100644
--- a/src/os/dir_darwin.go
+++ b/src/os/dir_darwin.go
@@ -54,6 +54,15 @@
 		if entptr == nil { // EOF
 			break
 		}
+		// Darwin may return a zero inode when a directory entry has been
+		// deleted but not yet removed from the directory. The man page for
+		// getdirentries(2) states that programs are responsible for skipping
+		// those entries:
+		//
+		//   Users of getdirentries() should skip entries with d_fileno = 0,
+		//   as such entries represent files which have been deleted but not
+		//   yet removed from the directory entry.
+		//
 		if dirent.Ino == 0 {
 			continue
 		}
diff --git a/src/os/dir_unix.go b/src/os/dir_unix.go
index 004b9fb..266a78a 100644
--- a/src/os/dir_unix.go
+++ b/src/os/dir_unix.go
@@ -89,7 +89,11 @@
 		if !ok {
 			break
 		}
-		if ino == 0 {
+		// When building to wasip1, the host runtime might be running on Windows
+		// or might expose a remote file system which does not have the concept
+		// of inodes. Therefore, we cannot make the assumption that it is safe
+		// to skip entries with zero inodes.
+		if ino == 0 && runtime.GOOS != "wasip1" {
 			continue
 		}
 		const namoff = uint64(unsafe.Offsetof(syscall.Dirent{}.Name))
diff --git a/src/os/env_test.go b/src/os/env_test.go
index 1b9e265..5809f4b 100644
--- a/src/os/env_test.go
+++ b/src/os/env_test.go
@@ -130,7 +130,7 @@
 	defer func(origEnv []string) {
 		for _, pair := range origEnv {
 			// Environment variables on Windows can begin with =
-			// https://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx
+			// https://devblogs.microsoft.com/oldnewthing/20100506-00/?p=14133
 			i := strings.Index(pair[1:], "=") + 1
 			if err := Setenv(pair[:i], pair[i+1:]); err != nil {
 				t.Errorf("Setenv(%q, %q) failed during reset: %v", pair[:i], pair[i+1:], err)
diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go
index cd978cc..8f11333 100644
--- a/src/runtime/crash_test.go
+++ b/src/runtime/crash_test.go
@@ -534,7 +534,7 @@
 
 	got, err := testenv.CleanCmdEnv(exec.Command(exe, "MemProf")).CombinedOutput()
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("testprog failed: %s, output:\n%s", err, got)
 	}
 	fn := strings.TrimSpace(string(got))
 	defer os.Remove(fn)
diff --git a/src/runtime/crash_unix_test.go b/src/runtime/crash_unix_test.go
index 07060b8..6bca2ac 100644
--- a/src/runtime/crash_unix_test.go
+++ b/src/runtime/crash_unix_test.go
@@ -76,7 +76,7 @@
 
 	testenv.MustHaveGoBuild(t)
 
-	if strings.Contains(os.Getenv("GCFLAGS"), "mayMoreStackPreempt") {
+	if strings.Contains(os.Getenv("GOFLAGS"), "mayMoreStackPreempt") {
 		// This test occasionally times out in this debug mode. This is probably
 		// revealing a real bug in the scheduler, but since it seems to only
 		// affect this test and this is itself a test of a debug mode, it's not
diff --git a/src/runtime/metrics/description.go b/src/runtime/metrics/description.go
index aea51c7..745691b 100644
--- a/src/runtime/metrics/description.go
+++ b/src/runtime/metrics/description.go
@@ -339,9 +339,11 @@
 		Kind: KindUint64,
 	},
 	{
-		Name:        "/memory/classes/heap/stacks:bytes",
-		Description: "Memory allocated from the heap that is reserved for stack space, whether or not it is currently in-use.",
-		Kind:        KindUint64,
+		Name: "/memory/classes/heap/stacks:bytes",
+		Description: "Memory allocated from the heap that is reserved for stack space, whether or not it is currently in-use. " +
+			"Currently, this represents all stack memory for goroutines. It also includes all OS thread stacks in non-cgo programs. " +
+			"Note that stacks may be allocated differently in the future, and this may change.",
+		Kind: KindUint64,
 	},
 	{
 		Name:        "/memory/classes/heap/unused:bytes",
@@ -374,9 +376,13 @@
 		Kind:        KindUint64,
 	},
 	{
-		Name:        "/memory/classes/os-stacks:bytes",
-		Description: "Stack memory allocated by the underlying operating system.",
-		Kind:        KindUint64,
+		Name: "/memory/classes/os-stacks:bytes",
+		Description: "Stack memory allocated by the underlying operating system. " +
+			"In non-cgo programs this metric is currently zero. This may change in the future." +
+			"In cgo programs this metric includes OS thread stacks allocated directly from the OS. " +
+			"Currently, this only accounts for one stack in c-shared and c-archive build modes, " +
+			"and other sources of stacks from the OS are not measured. This too may change in the future.",
+		Kind: KindUint64,
 	},
 	{
 		Name:        "/memory/classes/other:bytes",
diff --git a/src/runtime/metrics/doc.go b/src/runtime/metrics/doc.go
index 5238bce..5c52f78 100644
--- a/src/runtime/metrics/doc.go
+++ b/src/runtime/metrics/doc.go
@@ -318,7 +318,10 @@
 
 	/memory/classes/heap/stacks:bytes
 		Memory allocated from the heap that is reserved for stack space,
-		whether or not it is currently in-use.
+		whether or not it is currently in-use. Currently, this
+		represents all stack memory for goroutines. It also includes all
+		OS thread stacks in non-cgo programs. Note that stacks may be
+		allocated differently in the future, and this may change.
 
 	/memory/classes/heap/unused:bytes
 		Memory that is reserved for heap objects but is not currently
@@ -345,6 +348,12 @@
 
 	/memory/classes/os-stacks:bytes
 		Stack memory allocated by the underlying operating system.
+		In non-cgo programs this metric is currently zero. This may
+		change in the future.In cgo programs this metric includes
+		OS thread stacks allocated directly from the OS. Currently,
+		this only accounts for one stack in c-shared and c-archive build
+		modes, and other sources of stacks from the OS are not measured.
+		This too may change in the future.
 
 	/memory/classes/other:bytes
 		Memory used by execution trace buffers, structures for debugging
diff --git a/src/runtime/mstats.go b/src/runtime/mstats.go
index ab383dd..9cdc565 100644
--- a/src/runtime/mstats.go
+++ b/src/runtime/mstats.go
@@ -199,7 +199,17 @@
 	// StackSys is bytes of stack memory obtained from the OS.
 	//
 	// StackSys is StackInuse, plus any memory obtained directly
-	// from the OS for OS thread stacks (which should be minimal).
+	// from the OS for OS thread stacks.
+	//
+	// In non-cgo programs this metric is currently equal to StackInuse
+	// (but this should not be relied upon, and the value may change in
+	// the future).
+	//
+	// In cgo programs this metric includes OS thread stacks allocated
+	// directly from the OS. Currently, this only accounts for one stack in
+	// c-shared and c-archive build modes and other sources of stacks from
+	// the OS (notably, any allocated by C code) are not currently measured.
+	// Note this too may change in the future.
 	StackSys uint64
 
 	// Off-heap memory statistics.
@@ -347,6 +357,7 @@
 // which is a snapshot as of the most recently completed garbage
 // collection cycle.
 func ReadMemStats(m *MemStats) {
+	_ = m.Alloc // nil check test before we switch stacks, see issue 61158
 	stopTheWorld(stwReadMemStats)
 
 	systemstack(func() {
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index d6f8921..86df115 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -1147,6 +1147,7 @@
 
 // isExportedRuntime reports whether name is an exported runtime function.
 // It is only for runtime functions, so ASCII A-Z is fine.
+// TODO: this handles exported functions but not exported methods.
 func isExportedRuntime(name string) bool {
 	const n = len("runtime.")
 	return len(name) > n && name[:n] == "runtime." && 'A' <= name[n] && name[n] <= 'Z'
diff --git a/src/syscall/dirent.go b/src/syscall/dirent.go
index eee94bf..1a0f1ee 100644
--- a/src/syscall/dirent.go
+++ b/src/syscall/dirent.go
@@ -6,7 +6,10 @@
 
 package syscall
 
-import "unsafe"
+import (
+	"runtime"
+	"unsafe"
+)
 
 // readInt returns the size-bytes unsigned integer in native byte order at offset off.
 func readInt(b []byte, off, size uintptr) (u uint64, ok bool) {
@@ -75,7 +78,9 @@
 		if !ok {
 			break
 		}
-		if ino == 0 { // File absent in directory.
+		// See src/os/dir_unix.go for the reason why this condition is
+		// excluded on wasip1.
+		if ino == 0 && runtime.GOOS != "wasip1" { // File absent in directory.
 			continue
 		}
 		const namoff = uint64(unsafe.Offsetof(Dirent{}.Name))
diff --git a/src/syscall/env_windows.go b/src/syscall/env_windows.go
index 20d74b5..220a005 100644
--- a/src/syscall/env_windows.go
+++ b/src/syscall/env_windows.go
@@ -62,7 +62,7 @@
 	for _, s := range Environ() {
 		// Environment variables can begin with =
 		// so start looking for the separator = at j=1.
-		// https://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx
+		// https://devblogs.microsoft.com/oldnewthing/20100506-00/?p=14133
 		for j := 1; j < len(s); j++ {
 			if s[j] == '=' {
 				Unsetenv(s[0:j])
diff --git a/src/syscall/syscall_wasip1.go b/src/syscall/syscall_wasip1.go
index 5d19c00..e66afee 100644
--- a/src/syscall/syscall_wasip1.go
+++ b/src/syscall/syscall_wasip1.go
@@ -478,3 +478,16 @@
 	errno := fd_fdstat_set_flags(int32(fd), flags)
 	return errnoErr(errno)
 }
+
+type Rlimit struct {
+	Cur uint64
+	Max uint64
+}
+
+const (
+	RLIMIT_NOFILE = iota
+)
+
+func Getrlimit(which int, lim *Rlimit) error {
+	return ENOSYS
+}
diff --git a/test/codegen/floats.go b/test/codegen/floats.go
index 8147108..9cb62e0 100644
--- a/test/codegen/floats.go
+++ b/test/codegen/floats.go
@@ -20,6 +20,7 @@
 	// arm/7:"ADDD",-"MULD"
 	// arm64:"FADDD",-"FMULD"
 	// ppc64x:"FADD",-"FMUL"
+	// riscv64:"FADDD",-"FMULD"
 	return f * 2.0
 }
 
@@ -29,6 +30,7 @@
 	// arm/7:"MULD",-"DIVD"
 	// arm64:"FMULD",-"FDIVD"
 	// ppc64x:"FMUL",-"FDIV"
+	// riscv64:"FMULD",-"FDIVD"
 	x := f1 / 16.0
 
 	// 386/sse2:"MULSD",-"DIVSD"
@@ -36,6 +38,7 @@
 	// arm/7:"MULD",-"DIVD"
 	// arm64:"FMULD",-"FDIVD"
 	// ppc64x:"FMUL",-"FDIVD"
+	// riscv64:"FMULD",-"FDIVD"
 	y := f2 / 0.125
 
 	// 386/sse2:"ADDSD",-"DIVSD",-"MULSD"
@@ -43,6 +46,7 @@
 	// arm/7:"ADDD",-"MULD",-"DIVD"
 	// arm64:"FADDD",-"FMULD",-"FDIVD"
 	// ppc64x:"FADD",-"FMUL",-"FDIV"
+	// riscv64:"FADDD",-"FMULD",-"FDIVD"
 	z := f3 / 0.5
 
 	return x, y, z
diff --git a/test/codegen/math.go b/test/codegen/math.go
index 6a7d304..331ebbe 100644
--- a/test/codegen/math.go
+++ b/test/codegen/math.go
@@ -143,13 +143,13 @@
 	return math.FMA(x, y, -z)
 }
 
-func fnma(x, y, z float64) float64 {
-	// riscv64:"FNMADDD"
+func fnms(x, y, z float64) float64 {
+	// riscv64:"FNMSUBD",-"FNMADDD"
 	return math.FMA(-x, y, z)
 }
 
-func fnms(x, y, z float64) float64 {
-	// riscv64:"FNMSUBD"
+func fnma(x, y, z float64) float64 {
+	// riscv64:"FNMADDD",-"FNMSUBD"
 	return math.FMA(x, -y, -z)
 }