diff --git a/api/go1.21.txt b/api/go1.21.txt
index 6435d10914cfd9f82fb7c9e096e3415e80131d2b..c8ca3df2e65945a54810ce57eb0d5c4a6838b1b9 100644
--- a/api/go1.21.txt
+++ b/api/go1.21.txt
@@ -174,6 +174,7 @@ pkg go/build, type Package struct, Directives []Directive #56986
 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 8ee0c7035f173ed996eeb7cbe1865ec3cd2c560a..61b15dd963191f8145948ab7c3881386d327c196 100644
--- a/src/cmd/asm/internal/lex/slice.go
+++ b/src/cmd/asm/internal/lex/slice.go
@@ -65,7 +65,7 @@ func (s *Slice) Col() int {
 	//	#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 eb1f10de9606485b0e8aef2e63cf605a48c8b1ab..9a6fcebdc5151151995d1190451410d25c72e7ef 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 f1debe0c212c5c9ce4aa2cf9acec7a57ee0f58ef..ffbeb1df47618fc7c6bc5b789676624da8ccd5e2 100644
--- a/src/cmd/compile/internal/ssa/rewriteRISCV64.go
+++ b/src/cmd/compile/internal/ssa/rewriteRISCV64.go
@@ -3322,7 +3322,7 @@ func rewriteValueRISCV64_OpRISCV64FMADDD(v *Value) bool {
 	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 @@ func rewriteValueRISCV64_OpRISCV64FMADDD(v *Value) bool {
 			if !(neg.Uses == 1) {
 				continue
 			}
-			v.reset(OpRISCV64FNMADDD)
+			v.reset(OpRISCV64FNMSUBD)
 			v.AddArg3(x, y, z)
 			return true
 		}
@@ -3367,7 +3367,7 @@ func rewriteValueRISCV64_OpRISCV64FMSUBD(v *Value) bool {
 	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 @@ func rewriteValueRISCV64_OpRISCV64FMSUBD(v *Value) bool {
 			if !(neg.Uses == 1) {
 				continue
 			}
-			v.reset(OpRISCV64FNMSUBD)
+			v.reset(OpRISCV64FNMADDD)
 			v.AddArg3(x, y, z)
 			return true
 		}
@@ -3412,7 +3412,7 @@ func rewriteValueRISCV64_OpRISCV64FNMADDD(v *Value) bool {
 	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 @@ func rewriteValueRISCV64_OpRISCV64FNMADDD(v *Value) bool {
 			if !(neg.Uses == 1) {
 				continue
 			}
-			v.reset(OpRISCV64FMADDD)
+			v.reset(OpRISCV64FMSUBD)
 			v.AddArg3(x, y, z)
 			return true
 		}
@@ -3457,7 +3457,7 @@ func rewriteValueRISCV64_OpRISCV64FNMSUBD(v *Value) bool {
 	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 @@ func rewriteValueRISCV64_OpRISCV64FNMSUBD(v *Value) bool {
 			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 b2a9eb0dbc4c1de5d78f5f77edca0db76e267f51..0a2a49062b5ec001e6e8a7fa853e84e73f3256c5 100644
--- a/src/cmd/compile/internal/types2/check.go
+++ b/src/cmd/compile/internal/types2/check.go
@@ -11,6 +11,7 @@ import (
 	"errors"
 	"fmt"
 	"go/constant"
+	"internal/goversion"
 	. "internal/types/errors"
 )
 
@@ -231,19 +232,19 @@ func NewChecker(conf *Config, pkg *Package, info *Info) *Checker {
 		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 @@ func (check *Checker) Files(files []*syntax.File) error { return check.checkFile
 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 @@ func (check *Checker) checkFiles(files []*syntax.File) (err error) {
 		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 8bd42a5271517fc9d9159fb30a71e90e72443353..5e0ae213dcb2efa2d2888118f0307ccaa44071ea 100644
--- a/src/cmd/compile/internal/types2/issues_test.go
+++ b/src/cmd/compile/internal/types2/issues_test.go
@@ -497,14 +497,14 @@ func TestIssue43088(t *testing.T) {
 	//                 _ 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 TestIssue44515(t *testing.T) {
 }
 
 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
 
-	a := mustTypecheck(asrc, nil, nil)
-	conf := Config{Importer: importHelper{pkg: a, fallback: defaultImporter()}}
+import (
+	"a"
+	"html/template"
+)
 
+func _() {
 	// 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)
-	}
+	a.F(template /* ERRORx "cannot use.*html/template.* as .*text/template" */ .Template{})
+}
+`
+		csrc = `
+package c
 
-	// ...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)
+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)
+	imp := importHelper{pkg: a, fallback: defaultImporter()}
+
+	withImporter := func(cfg *Config) {
+		cfg.Importer = imp
 	}
+
+	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 61670f67181ec71fdccb6f94a45ffa01028bd257..e08099d81f078b9f44cdea7c3f1dbe3a10671a0f 100644
--- a/src/cmd/compile/internal/types2/package.go
+++ b/src/cmd/compile/internal/types2/package.go
@@ -10,13 +10,14 @@ import (
 
 // 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 @@ func (pkg *Package) Name() string { return pkg.name }
 // 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 af82b3fa7add821c952abca0347f94c9358327bb..740dbc92762aff8b6419660ca2c29d27eba3411b 100644
--- a/src/cmd/compile/internal/types2/sizeof_test.go
+++ b/src/cmd/compile/internal/types2/sizeof_test.go
@@ -47,7 +47,7 @@ func TestSizeof(t *testing.T) {
 
 		// 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 7d01b829a95e05342fb6fdf4c784f4b74a153681..e525f164705eb01b9b885aa1836a17b41de32d16 100644
--- a/src/cmd/compile/internal/types2/version.go
+++ b/src/cmd/compile/internal/types2/version.go
@@ -6,7 +6,6 @@ package types2
 
 import (
 	"cmd/compile/internal/syntax"
-	"errors"
 	"fmt"
 	"strings"
 )
@@ -44,23 +43,24 @@ var (
 	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 @@ func parseGoVersion(s string) (v version, err error) {
 		return
 	}
 	if i == 0 || s[i] != '.' {
-		return version{}, errVersionSyntax
+		return bad()
 	}
 	s = s[i+1:]
 	if s == "0" {
@@ -81,14 +81,15 @@ func parseGoVersion(s string) (v version, err error) {
 	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 0000000000000000000000000000000000000000..651758e1b0cff40f3b87bac69fb7279cbbf2dee0
--- /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 d38a051b2bb016aa1359262b0e9aaf0f4a9da08a..13d2a78a97d4d7d460d5d978a24c2cb5580fe567 100644
--- a/src/cmd/go/internal/work/exec.go
+++ b/src/cmd/go/internal/work/exec.go
@@ -1115,6 +1115,7 @@ type vetConfig struct {
 	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 @@ func buildVetConfig(a *Action, srcfiles []string) {
 		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 6043ad5353e404ccf19e51ed40011dea1207d333..26b4e0f490df3fa3df5c54bd05724b4080b5e9d4 100644
--- a/src/cmd/go/internal/work/gc.go
+++ b/src/cmd/go/internal/work/gc.go
@@ -85,19 +85,7 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg, embedcfg
 	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 a77d63dc5eb83f47bc4316116534626ec605d302..836fe83e2ec389e909c288c4d292e47a84298dde 100644
--- a/src/database/sql/sql.go
+++ b/src/database/sql/sql.go
@@ -2944,15 +2944,17 @@ func (rs *Rows) initContextClose(ctx, txctx context.Context) {
 	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 @@ func (rs *Rows) awaitDone(ctx, txctx context.Context) {
 	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 718056c3512606d47352b4ac8d96f953f2e59005..e6a5cd912ac361baeff7dbdacb650918987d8894 100644
--- a/src/database/sql/sql_test.go
+++ b/src/database/sql/sql_test.go
@@ -4493,6 +4493,31 @@ func TestContextCancelBetweenNextAndErr(t *testing.T) {
 	}
 }
 
+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 be8ac30f9daf9f444f5ea2f3c5b01e12fad8000a..2f335068b8a62fea40cc699681d333c983ab243b 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -286,7 +286,7 @@ var depsRules = `
 	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 5381b5db68765c1f01a4b1a4ec2e7ce3ea316483..3b0f5e4fdffbdc7dad16023bd8d8494697f6f043 100644
--- a/src/go/types/check.go
+++ b/src/go/types/check.go
@@ -12,6 +12,7 @@ import (
 	"go/ast"
 	"go/constant"
 	"go/token"
+	"internal/goversion"
 	. "internal/types/errors"
 )
 
@@ -233,20 +234,20 @@ func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Ch
 		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 @@ func (check *Checker) Files(files []*ast.File) error { return check.checkFiles(f
 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 @@ func (check *Checker) checkFiles(files []*ast.File) (err error) {
 		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 05a848be31d9cd968950d77012fc657b002944e7..75fda025ee1e31f216e96a2f664f6a518a8568f6 100644
--- a/src/go/types/generate_test.go
+++ b/src/go/types/generate_test.go
@@ -141,6 +141,7 @@ var filemap = map[string]action{
 	"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 7aa62fb7a3b715dca8ec60e4d719bc22ddfd4fd1..0f52d5f4893d185c53c59997fed722a438721106 100644
--- a/src/go/types/package.go
+++ b/src/go/types/package.go
@@ -12,13 +12,14 @@ import (
 
 // 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 @@ func (pkg *Package) Name() string { return pkg.name }
 // 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 f17a1781f574483e7ed3d71ff9f9765c957d6019..9e5b5f8b20398a243416e5a6cb84e4bce9c2022c 100644
--- a/src/go/types/sizeof_test.go
+++ b/src/go/types/sizeof_test.go
@@ -46,7 +46,7 @@ func TestSizeof(t *testing.T) {
 
 		// 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 07a42a79eed24bdd257c005776fa597b6af856d7..108d9b34a062aefcfb5774556aaf760bde7ad175 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 @@ var (
 	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 @@ func parseGoVersion(s string) (v version, err error) {
 		return
 	}
 	if i == 0 || s[i] != '.' {
-		return version{}, errVersionSyntax
+		return bad()
 	}
 	s = s[i+1:]
 	if s == "0" {
@@ -82,14 +82,15 @@ func parseGoVersion(s string) (v version, err error) {
 	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 0000000000000000000000000000000000000000..d25f7f5e670ae4a64daee7a88b8a0379674bb371
--- /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 dc4c2d92bd7126cfa27cfef7ca8b95ea31e99b20..e479ca8a4cf3faa359211d60bede46ab38d8747c 100644
--- a/src/log/slog/handler.go
+++ b/src/log/slog/handler.go
@@ -221,6 +221,11 @@ func (h *commonHandler) enabled(l Level) bool {
 }
 
 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 @@ func (s *handleState) appendNonBuiltIns(r Record) {
 	}
 	// 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 741e86a826c2d769d096d24b30435fda5596ea98..f43d841483991794ede14705856b4030852ad759 100644
--- a/src/log/slog/handler_test.go
+++ b/src/log/slog/handler_test.go
@@ -214,6 +214,28 @@ func TestJSONAndTextHandlers(t *testing.T) {
 			wantText: "msg=message h.a=1",
 			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),
@@ -281,6 +303,34 @@ func TestJSONAndTextHandlers(t *testing.T) {
 			wantText: "msg=message p1=1 s1.s2.a=one s1.s2.b=2",
 			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),
diff --git a/src/log/slog/logger_test.go b/src/log/slog/logger_test.go
index d151c0490cdce5d474675a420006e2769d8468d2..130f2e6ac8a5300f09486afa0bc43e457f0c1885 100644
--- a/src/log/slog/logger_test.go
+++ b/src/log/slog/logger_test.go
@@ -106,7 +106,7 @@ func TestConnections(t *testing.T) {
 	// 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 972552d5194e1778093566f9847b363e8a06fbcc..67b76f34e17fa5a11d14ba10c1892c7351ac3645 100644
--- a/src/log/slog/record.go
+++ b/src/log/slog/record.go
@@ -93,9 +93,17 @@ func (r Record) Attrs(f func(Attr) bool) {
 }
 
 // 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 @@ func (r *Record) AddAttrs(attrs ...Attr) {
 			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 71a59d2639bc826f8b3a9b71faa9bfd7e577fbf8..224848f695bc683f1be4286eec6f9069c95c1e24 100644
--- a/src/log/slog/value.go
+++ b/src/log/slog/value.go
@@ -164,9 +164,32 @@ func DurationValue(v time.Duration) Value {
 // 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 @@ func (v Value) Equal(w Value) bool {
 	}
 }
 
+// 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 615bed79d98b18af511b725ee97aee75583462d0..923a4e0cccfb430b1ff03cb911c76be210120b83 100644
--- a/src/log/slog/value_test.go
+++ b/src/log/slog/value_test.go
@@ -229,6 +229,18 @@ func TestZeroTime(t *testing.T) {
 	}
 }
 
+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 886267bc1756c108fc87f1551eeda06b60574b08..af3c38c2a690dda7da30e189bc58861c7c737849 100644
--- a/src/math/all_test.go
+++ b/src/math/all_test.go
@@ -2059,6 +2059,9 @@ var fmaC = []struct{ x, y, z, want float64 }{
 
 	// 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 @@ var fmaC = []struct{ x, y, z, want float64 }{
 	{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 @@ func TestFMA(t *testing.T) {
 	}
 }
 
+//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 ca0bf99f215603579286bf250cf6ae31c51cb193..ba03fbe8a93b27a2834b3248cc1c1fbb0804177a 100644
--- a/src/math/fma.go
+++ b/src/math/fma.go
@@ -132,6 +132,11 @@ func FMA(x, y, z float64) float64 {
 		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 bd483110b570919c76b8a4bb3f1afe55c2bae7ae..b26b11af8b4dcd156627d033128d6b527ad22fd0 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 1db166c9e3c2dfbba1bde6b4c0490abe514e66c4..77cc6355928b01dbbd8783df011710f5c10dd8d6 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 f3c075c83fd2a080f4c133a8012eedde9db8dfad..dab5144e5d7ae4fb60b0819df5b008c67e68f284 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 d5f34e530049038f83ac52ca5fe477093ad2fbe1..69b300410ab0e18e74b2b7e4a2ee682277c54537 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 1c9fb33b69d145f16272a1a84efcc8287b6719ef..91bb1b2620ab2e936703189cf60340e8d523a00b 100644
--- a/src/net/http/http_test.go
+++ b/src/net/http/http_test.go
@@ -48,35 +48,6 @@ func TestForeachHeaderElement(t *testing.T) {
 	}
 }
 
-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 4e9190493c735a790048c483e834a42582ae4778..bd868373c51dfa758049410590368d3dcef72aaf 100644
--- a/src/net/http/request.go
+++ b/src/net/http/request.go
@@ -17,7 +17,6 @@ import (
 	"io"
 	"mime"
 	"mime/multipart"
-	"net"
 	"net/http/httptrace"
 	"net/http/internal/ascii"
 	"net/textproto"
@@ -27,6 +26,7 @@ import (
 	"strings"
 	"sync"
 
+	"golang.org/x/net/http/httpguts"
 	"golang.org/x/net/idna"
 )
 
@@ -580,12 +580,19 @@ func (r *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, waitF
 	// 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 @@ func idnaASCII(v string) (string, error) {
 	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 78b968f23cfb61954cb71863b623a3a817d7c55e..0892bc255f9164e50baff7748b3aaa7606dacf68 100644
--- a/src/net/http/request_test.go
+++ b/src/net/http/request_test.go
@@ -775,15 +775,8 @@ func TestRequestBadHost(t *testing.T) {
 	}
 	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 172aba679be23e2d5163e82bda5ce0b0b9cb44b8..028fecc9611ea0010b48d5e1179ee02f2d04ad81 100644
--- a/src/net/http/transport_test.go
+++ b/src/net/http/transport_test.go
@@ -6731,3 +6731,22 @@ func testHandlerAbortRacesBodyRead(t *testing.T, mode testMode) {
 	}
 	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 45146e1c959add7916aebbb810cb76f2ecb35059..c27eae4ba5097e11460aae0f40f7206eb3c0a9df 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 dc75e0a3b68e566ac73f1a83e8e4772911743624..56ae11e961b6e050704548ce3e830b2aa131dcff 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 68d36966ca2ae46f7ce8e33f278f9f0c864ec5b9..908767a1f6535cab7583e74c833a2b3da0c3d076 100644
--- a/src/net/net_fake.go
+++ b/src/net/net_fake.go
@@ -15,8 +15,6 @@ import (
 	"sync"
 	"syscall"
 	"time"
-
-	"golang.org/x/net/dns/dnsmessage"
 )
 
 var listenersMu sync.Mutex
@@ -406,7 +404,3 @@ func (fd *fakeNetFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int,
 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 1fc0b50b7dfa52cb18359bd4b477039235621fdc..7ba108b664b83ac1d9ea695c6df4efe5394a4f1d 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 @@ type netFD struct {
 	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 deba3eb37f10b920adcf9f6343da0432cb9ef6f9..e6d5bda24bdd490c2744c5cf5e4782fd72f1a709 100644
--- a/src/os/dir_darwin.go
+++ b/src/os/dir_darwin.go
@@ -54,6 +54,15 @@ func (f *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEn
 		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 004b9fbb2be6a776f8a8e6a0e404a6ebdd62aab2..266a78acafce5ec9d7ed06aa3f4e99f9f43ce62a 100644
--- a/src/os/dir_unix.go
+++ b/src/os/dir_unix.go
@@ -89,7 +89,11 @@ func (f *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEn
 		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 1b9e26594cfe3482512b35ec4c657f6d735d8873..5809f4b866b73a38bdcea2c43ee3183f6c2cf5b7 100644
--- a/src/os/env_test.go
+++ b/src/os/env_test.go
@@ -130,7 +130,7 @@ func TestClearenv(t *testing.T) {
 	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 cd978cc34b55924ceb6ac2b400976470c5c3e141..8f11333b462535f4e94e2646c177d57dc1c834eb 100644
--- a/src/runtime/crash_test.go
+++ b/src/runtime/crash_test.go
@@ -534,7 +534,7 @@ func TestMemPprof(t *testing.T) {
 
 	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 07060b8fabaf8086295735fe3d42e8c075caaf00..6bca2ac66e480a9e5df4f146090e25031e9905a1 100644
--- a/src/runtime/crash_unix_test.go
+++ b/src/runtime/crash_unix_test.go
@@ -76,7 +76,7 @@ func TestCrashDumpsAllThreads(t *testing.T) {
 
 	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 aea51c7f7567b480552022bce14e9b27883f96f4..745691b24f9e31fcba3fb82277b7582b97f8cb53 100644
--- a/src/runtime/metrics/description.go
+++ b/src/runtime/metrics/description.go
@@ -339,9 +339,11 @@ var allDesc = []Description{
 		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 @@ var allDesc = []Description{
 		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 5238bcea8eaf087ed8ecfe1032b6914a23ee00c1..5c52f784778662a47937245b80810f260f617897 100644
--- a/src/runtime/metrics/doc.go
+++ b/src/runtime/metrics/doc.go
@@ -318,7 +318,10 @@ Below is the full list of supported metrics, ordered lexicographically.
 
 	/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 @@ Below is the full list of supported metrics, ordered lexicographically.
 
 	/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 ab383dd8e37e383728473caee6f29beb783359a1..9cdc56513719700345a5028ffb7d6f48e3a31170 100644
--- a/src/runtime/mstats.go
+++ b/src/runtime/mstats.go
@@ -199,7 +199,17 @@ type MemStats struct {
 	// 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 @@ func init() {
 // 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 d6f89210a4053494be2386620cb81d8bd1e439ea..86df1155b5c114bdcf3588039b1109e675b1d07b 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -1147,6 +1147,7 @@ func showfuncinfo(sf srcFunc, firstFrame bool, calleeID abi.FuncID) bool {
 
 // 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 eee94bf73c0c55670ca77066658abf5323419ab2..1a0f1eec11bf3dc6db993b552828c4a1f5c468e4 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 @@ func ParseDirent(buf []byte, max int, names []string) (consumed int, count int,
 		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 20d74b51e0107274f97b57a026af6d5b9eeb5127..220a005e1aaabb603851f38c0a65c1d5e954295b 100644
--- a/src/syscall/env_windows.go
+++ b/src/syscall/env_windows.go
@@ -62,7 +62,7 @@ func Clearenv() {
 	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 5d19c000ae6176656cffca0ec8850df8e4882463..e66afee5e9ad41333f8c33591bbe4d02bdaf7df9 100644
--- a/src/syscall/syscall_wasip1.go
+++ b/src/syscall/syscall_wasip1.go
@@ -478,3 +478,16 @@ func SetNonblock(fd int, nonblocking bool) error {
 	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 81471082d40eff26911b0021c930cdb7ef251348..9cb62e031a73f7db67e436e40744c8e47e4f478b 100644
--- a/test/codegen/floats.go
+++ b/test/codegen/floats.go
@@ -20,6 +20,7 @@ func Mul2(f float64) float64 {
 	// arm/7:"ADDD",-"MULD"
 	// arm64:"FADDD",-"FMULD"
 	// ppc64x:"FADD",-"FMUL"
+	// riscv64:"FADDD",-"FMULD"
 	return f * 2.0
 }
 
@@ -29,6 +30,7 @@ func DivPow2(f1, f2, f3 float64) (float64, float64, float64) {
 	// 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 @@ func DivPow2(f1, f2, f3 float64) (float64, float64, float64) {
 	// 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 @@ func DivPow2(f1, f2, f3 float64) (float64, float64, float64) {
 	// 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 6a7d304afdc676afdcc501f3816079b3c3ad624a..331ebbe6094bb18a5a567d485fb6da707eede1da 100644
--- a/test/codegen/math.go
+++ b/test/codegen/math.go
@@ -143,13 +143,13 @@ func fms(x, y, z float64) float64 {
 	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)
 }