Update linux-x86 Go prebuilts from ab/8003217 (1.18beta1)

https://ci.android.com/builds/branches/aosp-build-tools-release/grid?head=8003217&tail=8003217

Update script: toolchain/go/update-prebuilts.sh

Test: Treehugger presubmit
Change-Id: I4b89c374ccd78d5695b355cfe423d307fac1d2e9
diff --git a/test/run.go b/test/run.go
index d7f5d02..37be958 100644
--- a/test/run.go
+++ b/test/run.go
@@ -9,6 +9,7 @@
 
 import (
 	"bytes"
+	"encoding/json"
 	"errors"
 	"flag"
 	"fmt"
@@ -31,6 +32,10 @@
 	"unicode"
 )
 
+// CompilerDefaultGLevel is the -G level used by default when not overridden by a
+// command-line flag
+const CompilerDefaultGLevel = 3
+
 var (
 	verbose        = flag.Bool("v", false, "verbose. if set, parallelism is set to 1.")
 	keep           = flag.Bool("k", false, "keep. keep temporary directory.")
@@ -42,11 +47,55 @@
 	linkshared     = flag.Bool("linkshared", false, "")
 	updateErrors   = flag.Bool("update_errors", false, "update error messages in test file based on compiler output")
 	runoutputLimit = flag.Int("l", defaultRunOutputLimit(), "number of parallel runoutput tests to run")
+	force          = flag.Bool("f", false, "ignore expected-failure test lists")
+	generics       = flag.String("G", defaultGLevels, "a comma-separated list of -G compiler flags to test with")
 
 	shard  = flag.Int("shard", 0, "shard index to run. Only applicable if -shards is non-zero.")
 	shards = flag.Int("shards", 0, "number of shards. If 0, all tests are run. This is used by the continuous build.")
 )
 
+type envVars struct {
+	GOOS         string
+	GOARCH       string
+	GOEXPERIMENT string
+	CGO_ENABLED  string
+}
+
+var env = func() (res envVars) {
+	cmd := exec.Command("go", "env", "-json")
+	stdout, err := cmd.StdoutPipe()
+	if err != nil {
+		log.Fatal("StdoutPipe:", err)
+	}
+	if err := cmd.Start(); err != nil {
+		log.Fatal("Start:", err)
+	}
+	if err := json.NewDecoder(stdout).Decode(&res); err != nil {
+		log.Fatal("Decode:", err)
+	}
+	if err := cmd.Wait(); err != nil {
+		log.Fatal("Wait:", err)
+	}
+	return
+}()
+
+var unifiedEnabled, defaultGLevels = func() (bool, string) {
+	// TODO(mdempsky): This will give false negatives if the unified
+	// experiment is enabled by default, but presumably at that point we
+	// won't need to disable tests for it anymore anyway.
+	enabled := strings.Contains(","+env.GOEXPERIMENT+",", ",unified,")
+
+	// Test both -G=0 and -G=3 on the longtest builders, to make sure we
+	// don't accidentally break -G=0 mode until we're ready to remove it
+	// completely. But elsewhere, testing -G=3 alone should be enough.
+	glevels := "3"
+	if strings.Contains(os.Getenv("GO_BUILDER_NAME"), "longtest") {
+		glevels = "0,3"
+	}
+
+	return enabled, glevels
+}()
+
 // defaultAllCodeGen returns the default value of the -all_codegen
 // flag. By default, we prefer to be fast (returning false), except on
 // the linux-amd64 builder that's already very fast, so we get more
@@ -56,12 +105,13 @@
 }
 
 var (
-	goos, goarch string
-	cgoEnabled   bool
+	goos          = env.GOOS
+	goarch        = env.GOARCH
+	cgoEnabled, _ = strconv.ParseBool(env.CGO_ENABLED)
 
 	// dirs are the directories to look for *.go files in.
 	// TODO(bradfitz): just use all directories?
-	dirs = []string{".", "ken", "chan", "interface", "syntax", "dwarf", "fixedbugs", "codegen", "runtime", "abi", "typeparam"}
+	dirs = []string{".", "ken", "chan", "interface", "syntax", "dwarf", "fixedbugs", "codegen", "runtime", "abi", "typeparam", "typeparam/mdempsky"}
 
 	// ratec controls the max number of tests running at a time.
 	ratec chan bool
@@ -82,11 +132,13 @@
 func main() {
 	flag.Parse()
 
-	goos = getenv("GOOS", runtime.GOOS)
-	goarch = getenv("GOARCH", runtime.GOARCH)
-	cgoEnv, err := exec.Command(goTool(), "env", "CGO_ENABLED").Output()
-	if err == nil {
-		cgoEnabled, _ = strconv.ParseBool(strings.TrimSpace(string(cgoEnv)))
+	var glevels []int
+	for _, s := range strings.Split(*generics, ",") {
+		glevel, err := strconv.Atoi(s)
+		if err != nil {
+			log.Fatalf("invalid -G flag: %v", err)
+		}
+		glevels = append(glevels, glevel)
 	}
 
 	findExecCmd()
@@ -113,11 +165,11 @@
 			}
 			if fi, err := os.Stat(arg); err == nil && fi.IsDir() {
 				for _, baseGoFile := range goFiles(arg) {
-					tests = append(tests, startTest(arg, baseGoFile))
+					tests = append(tests, startTests(arg, baseGoFile, glevels)...)
 				}
 			} else if strings.HasSuffix(arg, ".go") {
 				dir, file := filepath.Split(arg)
-				tests = append(tests, startTest(dir, file))
+				tests = append(tests, startTests(dir, file, glevels)...)
 			} else {
 				log.Fatalf("can't yet deal with non-directory and non-go file %q", arg)
 			}
@@ -125,7 +177,7 @@
 	} else {
 		for _, dir := range dirs {
 			for _, baseGoFile := range goFiles(dir) {
-				tests = append(tests, startTest(dir, baseGoFile))
+				tests = append(tests, startTests(dir, baseGoFile, glevels)...)
 			}
 		}
 	}
@@ -142,8 +194,15 @@
 			status = "FAIL"
 		}
 		if test.err != nil {
-			status = "FAIL"
 			errStr = test.err.Error()
+			if test.expectFail {
+				errStr += " (expected)"
+			} else {
+				status = "FAIL"
+			}
+		} else if test.expectFail {
+			status = "FAIL"
+			errStr = "unexpected success"
 		}
 		if status == "FAIL" {
 			failed = true
@@ -151,7 +210,8 @@
 		resCount[status]++
 		dt := fmt.Sprintf("%.3fs", test.dt.Seconds())
 		if status == "FAIL" {
-			fmt.Printf("# go run run.go -- %s\n%s\nFAIL\t%s\t%s\n",
+			fmt.Printf("# go run run.go -G=%v %s\n%s\nFAIL\t%s\t%s\n",
+				test.glevel,
 				path.Join(test.dir, test.gofile),
 				errStr, test.goFileName(), dt)
 			continue
@@ -270,30 +330,78 @@
 	dir, gofile string
 	donec       chan bool // closed when done
 	dt          time.Duration
+	glevel      int // what -G level this test should use
 
 	src string
 
 	tempDir string
 	err     error
+
+	// expectFail indicates whether the (overall) test recipe is
+	// expected to fail under the current test configuration (e.g., -G=3
+	// or GOEXPERIMENT=unified).
+	expectFail bool
 }
 
-// startTest
-func startTest(dir, gofile string) *test {
-	t := &test{
-		dir:    dir,
-		gofile: gofile,
-		donec:  make(chan bool, 1),
+// initExpectFail initializes t.expectFail based on the build+test
+// configuration.
+func (t *test) initExpectFail(hasGFlag bool) {
+	if *force {
+		return
 	}
-	if toRun == nil {
-		toRun = make(chan *test, maxTests)
-		go runTests()
+
+	if t.glevel == 0 && !hasGFlag && !unifiedEnabled {
+		// tests should always pass when run w/o types2 (i.e., using the
+		// legacy typechecker, option -G=0).
+		return
 	}
-	select {
-	case toRun <- t:
-	default:
-		panic("toRun buffer size (maxTests) is too small")
+
+	failureSets := []map[string]bool{types2Failures}
+
+	// Note: gccgo supports more 32-bit architectures than this, but
+	// hopefully the 32-bit failures are fixed before this matters.
+	switch goarch {
+	case "386", "arm", "mips", "mipsle":
+		failureSets = append(failureSets, types2Failures32Bit)
 	}
-	return t
+
+	if unifiedEnabled {
+		failureSets = append(failureSets, unifiedFailures)
+	} else {
+		failureSets = append(failureSets, g3Failures)
+	}
+
+	filename := strings.Replace(t.goFileName(), "\\", "/", -1) // goFileName() uses \ on Windows
+
+	for _, set := range failureSets {
+		if set[filename] {
+			t.expectFail = true
+			return
+		}
+	}
+}
+
+func startTests(dir, gofile string, glevels []int) []*test {
+	tests := make([]*test, len(glevels))
+	for i, glevel := range glevels {
+		t := &test{
+			dir:    dir,
+			gofile: gofile,
+			glevel: glevel,
+			donec:  make(chan bool, 1),
+		}
+		if toRun == nil {
+			toRun = make(chan *test, maxTests)
+			go runTests()
+		}
+		select {
+		case toRun <- t:
+		default:
+			panic("toRun buffer size (maxTests) is too small")
+		}
+		tests[i] = t
+	}
+	return tests
 }
 
 // runTests runs tests in parallel, but respecting the order they
@@ -427,9 +535,9 @@
 	if name == "" {
 		return false
 	}
-	if i := strings.Index(name, ","); i >= 0 {
+	if first, rest, ok := strings.Cut(name, ","); ok {
 		// comma-separated list
-		return ctxt.match(name[:i]) && ctxt.match(name[i+1:])
+		return ctxt.match(first) && ctxt.match(rest)
 	}
 	if strings.HasPrefix(name, "!!") { // bad syntax, reject always
 		return false
@@ -480,12 +588,16 @@
 // This must match the flags used for building the standard library,
 // or else the commands will rebuild any needed packages (like runtime)
 // over and over.
-func goGcflags() string {
-	return "-gcflags=all=" + os.Getenv("GO_GCFLAGS")
+func (t *test) goGcflags() string {
+	flags := os.Getenv("GO_GCFLAGS")
+	if t.glevel != CompilerDefaultGLevel {
+		flags = fmt.Sprintf("%s -G=%v", flags, t.glevel)
+	}
+	return "-gcflags=all=" + flags
 }
 
-func goGcflagsIsEmpty() bool {
-	return "" == os.Getenv("GO_GCFLAGS")
+func (t *test) goGcflagsIsEmpty() bool {
+	return "" == os.Getenv("GO_GCFLAGS") && t.glevel == CompilerDefaultGLevel
 }
 
 var errTimeout = errors.New("command exceeded time limit")
@@ -510,24 +622,23 @@
 	}
 
 	// Execution recipe stops at first blank line.
-	pos := strings.Index(t.src, "\n\n")
-	if pos == -1 {
+	action, _, ok := strings.Cut(t.src, "\n\n")
+	if !ok {
 		t.err = fmt.Errorf("double newline ending execution recipe not found in %s", t.goFileName())
 		return
 	}
-	action := t.src[:pos]
-	if nl := strings.Index(action, "\n"); nl >= 0 && strings.Contains(action[:nl], "+build") {
+	if firstLine, rest, ok := strings.Cut(action, "\n"); ok && strings.Contains(firstLine, "+build") {
 		// skip first line
-		action = action[nl+1:]
+		action = rest
 	}
 	action = strings.TrimPrefix(action, "//")
 
 	// Check for build constraints only up to the actual code.
-	pkgPos := strings.Index(t.src, "\npackage")
-	if pkgPos == -1 {
-		pkgPos = pos // some files are intentionally malformed
+	header, _, ok := strings.Cut(t.src, "\npackage")
+	if !ok {
+		header = action // some files are intentionally malformed
 	}
-	if ok, why := shouldTest(t.src[:pkgPos], goos, goarch); !ok {
+	if ok, why := shouldTest(header, goos, goarch); !ok {
 		if *showSkips {
 			fmt.Printf("%-20s %-20s: %s\n", "skip", t.goFileName(), why)
 		}
@@ -541,7 +652,11 @@
 	singlefilepkgs := false
 	setpkgpaths := false
 	localImports := true
-	f := strings.Fields(action)
+	f, err := splitQuoted(action)
+	if err != nil {
+		t.err = fmt.Errorf("invalid test recipe: %v", err)
+		return
+	}
 	if len(f) > 0 {
 		action = f[0]
 		args = f[1:]
@@ -569,6 +684,8 @@
 		return
 	}
 
+	goexp := env.GOEXPERIMENT
+
 	// collect flags
 	for len(args) > 0 && strings.HasPrefix(args[0], "-") {
 		switch args[0] {
@@ -595,7 +712,11 @@
 			}
 		case "-goexperiment": // set GOEXPERIMENT environment
 			args = args[1:]
-			runenv = append(runenv, "GOEXPERIMENT="+args[0])
+			if goexp != "" {
+				goexp += ","
+			}
+			goexp += args[0]
+			runenv = append(runenv, "GOEXPERIMENT="+goexp)
 
 		default:
 			flags = append(flags, args[0])
@@ -616,6 +737,60 @@
 		}
 	}
 
+	type Tool int
+
+	const (
+		_ Tool = iota
+		AsmCheck
+		Build
+		Run
+		Compile
+	)
+
+	// validForGLevel reports whether the current test is valid to run
+	// at the specified -G level. If so, it may update flags as
+	// necessary to test with -G.
+	validForGLevel := func(tool Tool) bool {
+		hasGFlag := false
+		for _, flag := range flags {
+			if strings.Contains(flag, "-G") {
+				hasGFlag = true
+			}
+		}
+
+		// In unified IR mode, run the test regardless of explicit -G flag.
+		if !unifiedEnabled && hasGFlag && t.glevel != CompilerDefaultGLevel {
+			// test provides explicit -G flag already; don't run again
+			if *verbose {
+				fmt.Printf("excl\t%s\n", t.goFileName())
+			}
+			return false
+		}
+
+		t.initExpectFail(hasGFlag)
+
+		switch tool {
+		case Build, Run:
+			// ok; handled in goGcflags
+
+		case Compile:
+			if !hasGFlag {
+				flags = append(flags, fmt.Sprintf("-G=%v", t.glevel))
+			}
+
+		default:
+			if t.glevel != CompilerDefaultGLevel {
+				// we don't know how to add -G for this test yet
+				if *verbose {
+					fmt.Printf("excl\t%s\n", t.goFileName())
+				}
+				return false
+			}
+		}
+
+		return true
+	}
+
 	t.makeTempDir()
 	if !*keep {
 		defer os.RemoveAll(t.tempDir)
@@ -692,6 +867,10 @@
 		t.err = fmt.Errorf("unimplemented action %q", action)
 
 	case "asmcheck":
+		if !validForGLevel(AsmCheck) {
+			return
+		}
+
 		// Compile Go file and match the generated assembly
 		// against a set of regexps in comments.
 		ops := t.wantedAsmOpcodes(long)
@@ -746,6 +925,10 @@
 		return
 
 	case "errorcheck":
+		if !validForGLevel(Compile) {
+			return
+		}
+
 		// Compile Go file.
 		// Fail if wantError is true and compilation was successful and vice versa.
 		// Match errors produced by gc against errors in comments.
@@ -774,72 +957,20 @@
 			t.updateErrors(string(out), long)
 		}
 		t.err = t.errorCheck(string(out), wantAuto, long, t.gofile)
-		if t.err != nil {
-			return // don't hide error if run below succeeds
-		}
-
-		// The following is temporary scaffolding to get types2 typechecker
-		// up and running against the existing test cases. The explicitly
-		// listed files don't pass yet, usually because the error messages
-		// are slightly different (this list is not complete). Any errorcheck
-		// tests that require output from analysis phases past initial type-
-		// checking are also excluded since these phases are not running yet.
-		// We can get rid of this code once types2 is fully plugged in.
-
-		// For now we're done when we can't handle the file or some of the flags.
-		// The first goal is to eliminate the excluded list; the second goal is to
-		// eliminate the flag list.
-
-		// Excluded files.
-		filename := strings.Replace(t.goFileName(), "\\", "/", -1) // goFileName() uses \ on Windows
-		if excluded[filename] {
-			if *verbose {
-				fmt.Printf("excl\t%s\n", filename)
-			}
-			return // cannot handle file yet
-		}
-
-		// Excluded flags.
-		for _, flag := range flags {
-			for _, pattern := range []string{
-				"-m",
-			} {
-				if strings.Contains(flag, pattern) {
-					if *verbose {
-						fmt.Printf("excl\t%s\t%s\n", filename, flags)
-					}
-					return // cannot handle flag
-				}
-			}
-		}
-
-		// Run errorcheck again with -G option (new typechecker).
-		cmdline = []string{goTool(), "tool", "compile", "-G=3", "-C", "-e", "-o", "a.o"}
-		// No need to add -dynlink even if linkshared if we're just checking for errors...
-		cmdline = append(cmdline, flags...)
-		cmdline = append(cmdline, long)
-		out, err = runcmd(cmdline...)
-		if wantError {
-			if err == nil {
-				t.err = fmt.Errorf("compilation succeeded unexpectedly\n%s", out)
-				return
-			}
-		} else {
-			if err != nil {
-				t.err = err
-				return
-			}
-		}
-		if *updateErrors {
-			t.updateErrors(string(out), long)
-		}
-		t.err = t.errorCheck(string(out), wantAuto, long, t.gofile)
 
 	case "compile":
+		if !validForGLevel(Compile) {
+			return
+		}
+
 		// Compile Go file.
 		_, t.err = compileFile(runcmd, long, flags)
 
 	case "compiledir":
+		if !validForGLevel(Compile) {
+			return
+		}
+
 		// Compile all files in the directory as packages in lexicographic order.
 		longdir := filepath.Join(cwd, t.goDirName())
 		pkgs, err := goDirPackages(longdir, singlefilepkgs)
@@ -855,6 +986,10 @@
 		}
 
 	case "errorcheckdir", "errorcheckandrundir":
+		if !validForGLevel(Compile) {
+			return
+		}
+
 		flags = append(flags, "-d=panic")
 		// Compile and errorCheck all files in the directory as packages in lexicographic order.
 		// If errorcheckdir and wantError, compilation of the last package must fail.
@@ -900,6 +1035,10 @@
 		fallthrough
 
 	case "rundir":
+		if !validForGLevel(Run) {
+			return
+		}
+
 		// Compile all files in the directory as packages in lexicographic order.
 		// In case of errorcheckandrundir, ignore failed compilation of the package before the last.
 		// Link as if the last file is the main package, run it.
@@ -958,6 +1097,10 @@
 		}
 
 	case "runindir":
+		if !validForGLevel(Run) {
+			return
+		}
+
 		// Make a shallow copy of t.goDirName() in its own module and GOPATH, and
 		// run "go run ." in it. The module path (and hence import path prefix) of
 		// the copy is equal to the basename of the source directory.
@@ -983,7 +1126,7 @@
 			return
 		}
 
-		cmd := []string{goTool(), "run", goGcflags()}
+		cmd := []string{goTool(), "run", t.goGcflags()}
 		if *linkshared {
 			cmd = append(cmd, "-linkshared")
 		}
@@ -997,13 +1140,21 @@
 		t.checkExpectedOutput(out)
 
 	case "build":
+		if !validForGLevel(Build) {
+			return
+		}
+
 		// Build Go file.
-		_, err := runcmd(goTool(), "build", goGcflags(), "-o", "a.exe", long)
+		_, err := runcmd(goTool(), "build", t.goGcflags(), "-o", "a.exe", long)
 		if err != nil {
 			t.err = err
 		}
 
 	case "builddir", "buildrundir":
+		if !validForGLevel(Build) {
+			return
+		}
+
 		// Build an executable from all the .go and .s files in a subdirectory.
 		// Run it and verify its output in the buildrundir case.
 		longdir := filepath.Join(cwd, t.goDirName())
@@ -1083,10 +1234,14 @@
 		}
 
 	case "buildrun":
+		if !validForGLevel(Build) {
+			return
+		}
+
 		// Build an executable from Go file, then run it, verify its output.
 		// Useful for timeout tests where failure mode is infinite loop.
 		// TODO: not supported on NaCl
-		cmd := []string{goTool(), "build", goGcflags(), "-o", "a.exe"}
+		cmd := []string{goTool(), "build", t.goGcflags(), "-o", "a.exe"}
 		if *linkshared {
 			cmd = append(cmd, "-linkshared")
 		}
@@ -1108,13 +1263,17 @@
 		t.checkExpectedOutput(out)
 
 	case "run":
+		if !validForGLevel(Run) {
+			return
+		}
+
 		// Run Go file if no special go command flags are provided;
 		// otherwise build an executable and run it.
 		// Verify the output.
 		runInDir = ""
 		var out []byte
 		var err error
-		if len(flags)+len(args) == 0 && goGcflagsIsEmpty() && !*linkshared && goarch == runtime.GOARCH && goos == runtime.GOOS {
+		if len(flags)+len(args) == 0 && t.goGcflagsIsEmpty() && !*linkshared && goarch == runtime.GOARCH && goos == runtime.GOOS && goexp == env.GOEXPERIMENT {
 			// If we're not using special go command flags,
 			// skip all the go command machinery.
 			// This avoids any time the go command would
@@ -1136,7 +1295,7 @@
 			}
 			out, err = runcmd(append([]string{exe}, args...)...)
 		} else {
-			cmd := []string{goTool(), "run", goGcflags()}
+			cmd := []string{goTool(), "run", t.goGcflags()}
 			if *linkshared {
 				cmd = append(cmd, "-linkshared")
 			}
@@ -1151,6 +1310,10 @@
 		t.checkExpectedOutput(out)
 
 	case "runoutput":
+		if !validForGLevel(Run) {
+			return
+		}
+
 		// Run Go file and write its output into temporary Go file.
 		// Run generated Go file and verify its output.
 		rungatec <- true
@@ -1158,7 +1321,7 @@
 			<-rungatec
 		}()
 		runInDir = ""
-		cmd := []string{goTool(), "run", goGcflags()}
+		cmd := []string{goTool(), "run", t.goGcflags()}
 		if *linkshared {
 			cmd = append(cmd, "-linkshared")
 		}
@@ -1173,7 +1336,7 @@
 			t.err = fmt.Errorf("write tempfile:%s", err)
 			return
 		}
-		cmd = []string{goTool(), "run", goGcflags()}
+		cmd = []string{goTool(), "run", t.goGcflags()}
 		if *linkshared {
 			cmd = append(cmd, "-linkshared")
 		}
@@ -1186,10 +1349,14 @@
 		t.checkExpectedOutput(out)
 
 	case "errorcheckoutput":
+		if !validForGLevel(Compile) {
+			return
+		}
+
 		// Run Go file and write its output into temporary Go file.
 		// Compile and errorCheck generated Go file.
 		runInDir = ""
-		cmd := []string{goTool(), "run", goGcflags()}
+		cmd := []string{goTool(), "run", t.goGcflags()}
 		if *linkshared {
 			cmd = append(cmd, "-linkshared")
 		}
@@ -1348,8 +1515,8 @@
 			// Assume errmsg says "file:line: foo".
 			// Cut leading "file:line: " to avoid accidental matching of file name instead of message.
 			text := errmsg
-			if i := strings.Index(text, " "); i >= 0 {
-				text = text[i+1:]
+			if _, suffix, ok := strings.Cut(text, " "); ok {
+				text = suffix
 			}
 			if we.re.MatchString(text) {
 				matched = true
@@ -1394,31 +1561,26 @@
 	}
 	lines := strings.Split(string(src), "\n")
 	// Remove old errors.
-	for i, ln := range lines {
-		pos := strings.Index(ln, " // ERROR ")
-		if pos >= 0 {
-			lines[i] = ln[:pos]
-		}
+	for i := range lines {
+		lines[i], _, _ = strings.Cut(lines[i], " // ERROR ")
 	}
 	// Parse new errors.
 	errors := make(map[int]map[string]bool)
 	tmpRe := regexp.MustCompile(`autotmp_[0-9]+`)
 	for _, errStr := range splitOutput(out, false) {
-		colon1 := strings.Index(errStr, ":")
-		if colon1 < 0 || errStr[:colon1] != file {
+		errFile, rest, ok := strings.Cut(errStr, ":")
+		if !ok || errFile != file {
 			continue
 		}
-		colon2 := strings.Index(errStr[colon1+1:], ":")
-		if colon2 < 0 {
+		lineStr, msg, ok := strings.Cut(rest, ":")
+		if !ok {
 			continue
 		}
-		colon2 += colon1 + 1
-		line, err := strconv.Atoi(errStr[colon1+1 : colon2])
+		line, err := strconv.Atoi(lineStr)
 		line--
 		if err != nil || line < 0 || line >= len(lines) {
 			continue
 		}
-		msg := errStr[colon2+2:]
 		msg = strings.Replace(msg, file, base, -1) // normalize file mentions in error itself
 		msg = strings.TrimLeft(msg, " \t")
 		for _, r := range []string{`\`, `*`, `+`, `?`, `[`, `]`, `(`, `)`} {
@@ -1585,7 +1747,7 @@
 	// are the supported variants.
 	archVariants = map[string][]string{
 		"386":     {"GO386", "sse2", "softfloat"},
-		"amd64":   {},
+		"amd64":   {"GOAMD64", "v1", "v2", "v3", "v4"},
 		"arm":     {"GOARM", "5", "6", "7"},
 		"arm64":   {},
 		"mips":    {"GOMIPS", "hardfloat", "softfloat"},
@@ -1594,6 +1756,7 @@
 		"ppc64le": {"GOPPC64", "power8", "power9"},
 		"s390x":   {},
 		"wasm":    {},
+		"riscv64": {},
 	}
 )
 
@@ -1941,66 +2104,157 @@
 	})
 }
 
+// The following is temporary scaffolding to get types2 typechecker
+// up and running against the existing test cases. The explicitly
+// listed files don't pass yet, usually because the error messages
+// are slightly different (this list is not complete). Any errorcheck
+// tests that require output from analysis phases past initial type-
+// checking are also excluded since these phases are not running yet.
+// We can get rid of this code once types2 is fully plugged in.
+
 // List of files that the compiler cannot errorcheck with the new typechecker (compiler -G option).
 // Temporary scaffolding until we pass all the tests at which point this map can be removed.
-var excluded = map[string]bool{
-	"complit1.go":     true, // types2 reports extra errors
-	"const2.go":       true, // types2 not run after syntax errors
-	"ddd1.go":         true, // issue #42987
-	"directive.go":    true, // misplaced compiler directive checks
-	"float_lit3.go":   true, // types2 reports extra errors
-	"import1.go":      true, // types2 reports extra errors
-	"import5.go":      true, // issue #42988
-	"import6.go":      true, // issue #43109
-	"initializerr.go": true, // types2 reports extra errors
-	"linkname2.go":    true, // error reported by noder (not running for types2 errorcheck test)
-	"notinheap.go":    true, // types2 doesn't report errors about conversions that are invalid due to //go:notinheap
-	"shift1.go":       true, // issue #42989
-	"typecheck.go":    true, // invalid function is not causing errors when called
-	"writebarrier.go": true, // correct diagnostics, but different lines (probably irgen's fault)
+var types2Failures = setOf(
+	"import1.go",      // types2 reports extra errors
+	"import6.go",      // issue #43109
+	"initializerr.go", // types2 reports extra errors
+	"notinheap.go",    // types2 doesn't report errors about conversions that are invalid due to //go:notinheap
+	"shift1.go",       // mostly just different wording, but reports two new errors.
+	"typecheck.go",    // invalid function is not causing errors when called
 
-	"fixedbugs/bug176.go":    true, // types2 reports all errors (pref: types2)
-	"fixedbugs/bug195.go":    true, // types2 reports slightly different (but correct) bugs
-	"fixedbugs/bug228.go":    true, // types2 not run after syntax errors
-	"fixedbugs/bug231.go":    true, // types2 bug? (same error reported twice)
-	"fixedbugs/bug255.go":    true, // types2 reports extra errors
-	"fixedbugs/bug351.go":    true, // types2 reports extra errors
-	"fixedbugs/bug374.go":    true, // types2 reports extra errors
-	"fixedbugs/bug385_32.go": true, // types2 doesn't produce missing error "type .* too large" (32-bit specific)
-	"fixedbugs/bug388.go":    true, // types2 not run due to syntax errors
-	"fixedbugs/bug412.go":    true, // types2 produces a follow-on error
+	"fixedbugs/bug176.go", // types2 reports all errors (pref: types2)
+	"fixedbugs/bug195.go", // types2 reports slightly different (but correct) bugs
+	"fixedbugs/bug228.go", // types2 doesn't run when there are syntax errors
+	"fixedbugs/bug231.go", // types2 bug? (same error reported twice)
+	"fixedbugs/bug255.go", // types2 reports extra errors
+	"fixedbugs/bug388.go", // types2 not run due to syntax errors
+	"fixedbugs/bug412.go", // types2 produces a follow-on error
 
-	"fixedbugs/issue11590.go":  true, // types2 doesn't report a follow-on error (pref: types2)
-	"fixedbugs/issue11610.go":  true, // types2 not run after syntax errors
-	"fixedbugs/issue11614.go":  true, // types2 reports an extra error
-	"fixedbugs/issue13415.go":  true, // declared but not used conflict
-	"fixedbugs/issue14520.go":  true, // missing import path error by types2
-	"fixedbugs/issue16428.go":  true, // types2 reports two instead of one error
-	"fixedbugs/issue17038.go":  true, // types2 doesn't report a follow-on error (pref: types2)
-	"fixedbugs/issue17645.go":  true, // multiple errors on same line
-	"fixedbugs/issue18331.go":  true, // missing error about misuse of //go:noescape (irgen needs code from noder)
-	"fixedbugs/issue18393.go":  true, // types2 not run after syntax errors
-	"fixedbugs/issue19012.go":  true, // multiple errors on same line
-	"fixedbugs/issue20233.go":  true, // types2 reports two instead of one error (pref: compiler)
-	"fixedbugs/issue20245.go":  true, // types2 reports two instead of one error (pref: compiler)
-	"fixedbugs/issue20250.go":  true, // correct diagnostics, but different lines (probably irgen's fault)
-	"fixedbugs/issue21979.go":  true, // types2 doesn't report a follow-on error (pref: types2)
-	"fixedbugs/issue23732.go":  true, // types2 reports different (but ok) line numbers
-	"fixedbugs/issue25958.go":  true, // types2 doesn't report a follow-on error (pref: types2)
-	"fixedbugs/issue28079b.go": true, // types2 reports follow-on errors
-	"fixedbugs/issue28268.go":  true, // types2 reports follow-on errors
-	"fixedbugs/issue33460.go":  true, // types2 reports alternative positions in separate error
-	"fixedbugs/issue41575.go":  true, // types2 reports alternative positions in separate error
-	"fixedbugs/issue42058a.go": true, // types2 doesn't report "channel element type too large"
-	"fixedbugs/issue42058b.go": true, // types2 doesn't report "channel element type too large"
-	"fixedbugs/issue4232.go":   true, // types2 reports (correct) extra errors
-	"fixedbugs/issue4452.go":   true, // types2 reports (correct) extra errors
-	"fixedbugs/issue5609.go":   true, // types2 needs a better error message
-	"fixedbugs/issue6889.go":   true, // types2 can handle this without constant overflow
-	"fixedbugs/issue7525.go":   true, // types2 reports init cycle error on different line - ok otherwise
-	"fixedbugs/issue7525b.go":  true, // types2 reports init cycle error on different line - ok otherwise
-	"fixedbugs/issue7525c.go":  true, // types2 reports init cycle error on different line - ok otherwise
-	"fixedbugs/issue7525d.go":  true, // types2 reports init cycle error on different line - ok otherwise
-	"fixedbugs/issue7525e.go":  true, // types2 reports init cycle error on different line - ok otherwise
-	"fixedbugs/issue46749.go":  true, // types2 reports can not convert error instead of type mismatched
+	"fixedbugs/issue10700.go",  // types2 reports ok hint, but does not match regexp
+	"fixedbugs/issue11590.go",  // types2 doesn't report a follow-on error (pref: types2)
+	"fixedbugs/issue11610.go",  // types2 not run after syntax errors
+	"fixedbugs/issue11614.go",  // types2 reports an extra error
+	"fixedbugs/issue14520.go",  // missing import path error by types2
+	"fixedbugs/issue17038.go",  // types2 doesn't report a follow-on error (pref: types2)
+	"fixedbugs/issue18331.go",  // missing error about misuse of //go:noescape (irgen needs code from noder)
+	"fixedbugs/issue18419.go",  // types2 reports no field or method member, but should say unexported
+	"fixedbugs/issue19012.go",  // multiple errors on same line
+	"fixedbugs/issue20233.go",  // types2 reports two instead of one error (pref: compiler)
+	"fixedbugs/issue20245.go",  // types2 reports two instead of one error (pref: compiler)
+	"fixedbugs/issue21979.go",  // types2 doesn't report a follow-on error (pref: types2)
+	"fixedbugs/issue23732.go",  // types2 reports different (but ok) line numbers
+	"fixedbugs/issue25958.go",  // types2 doesn't report a follow-on error (pref: types2)
+	"fixedbugs/issue28079b.go", // types2 reports follow-on errors
+	"fixedbugs/issue28268.go",  // types2 reports follow-on errors
+	"fixedbugs/issue31053.go",  // types2 reports "unknown field" instead of "cannot refer to unexported field"
+	"fixedbugs/issue33460.go",  // types2 reports alternative positions in separate error
+	"fixedbugs/issue4232.go",   // types2 reports (correct) extra errors
+	"fixedbugs/issue4452.go",   // types2 reports (correct) extra errors
+	"fixedbugs/issue4510.go",   // types2 reports different (but ok) line numbers
+	"fixedbugs/issue7525b.go",  // types2 reports init cycle error on different line - ok otherwise
+	"fixedbugs/issue7525c.go",  // types2 reports init cycle error on different line - ok otherwise
+	"fixedbugs/issue7525d.go",  // types2 reports init cycle error on different line - ok otherwise
+	"fixedbugs/issue7525e.go",  // types2 reports init cycle error on different line - ok otherwise
+	"fixedbugs/issue7525.go",   // types2 reports init cycle error on different line - ok otherwise
+)
+
+var types2Failures32Bit = setOf(
+	"printbig.go",             // large untyped int passed to print (32-bit)
+	"fixedbugs/bug114.go",     // large untyped int passed to println (32-bit)
+	"fixedbugs/issue23305.go", // large untyped int passed to println (32-bit)
+)
+
+var g3Failures = setOf(
+	"typeparam/nested.go", // -G=3 doesn't support function-local types with generics
+)
+
+var unifiedFailures = setOf(
+	"closure3.go",  // unified IR numbers closures differently than -d=inlfuncswithclosures
+	"escape4.go",   // unified IR can inline f5 and f6; test doesn't expect this
+	"inline.go",    // unified IR reports function literal diagnostics on different lines than -d=inlfuncswithclosures
+	"linkname3.go", // unified IR is missing some linkname errors
+
+	"fixedbugs/issue42284.go",  // prints "T(0) does not escape", but test expects "a.I(a.T(0)) does not escape"
+	"fixedbugs/issue7921.go",   // prints "… escapes to heap", but test expects "string(…) escapes to heap"
+	"typeparam/issue48538.go",  // assertion failure, interprets struct key as closure variable
+	"typeparam/issue47631.go",  // unified IR can handle local type declarations
+	"fixedbugs/issue42058a.go", // unified IR doesn't report channel element too large
+	"fixedbugs/issue42058b.go", // unified IR doesn't report channel element too large
+	"fixedbugs/issue49767.go",  // unified IR doesn't report channel element too large
+	"fixedbugs/issue49814.go",  // unified IR doesn't report array type too large
+	"typeparam/issue50002.go",  // pure stenciling leads to a static type assertion error
+	"typeparam/typeswitch1.go", // duplicate case failure due to stenciling
+	"typeparam/typeswitch2.go", // duplicate case failure due to stenciling
+	"typeparam/typeswitch3.go", // duplicate case failure due to stenciling
+	"typeparam/typeswitch4.go", // duplicate case failure due to stenciling
+)
+
+func setOf(keys ...string) map[string]bool {
+	m := make(map[string]bool, len(keys))
+	for _, key := range keys {
+		m[key] = true
+	}
+	return m
+}
+
+// splitQuoted splits the string s around each instance of one or more consecutive
+// white space characters while taking into account quotes and escaping, and
+// returns an array of substrings of s or an empty list if s contains only white space.
+// Single quotes and double quotes are recognized to prevent splitting within the
+// quoted region, and are removed from the resulting substrings. If a quote in s
+// isn't closed err will be set and r will have the unclosed argument as the
+// last element. The backslash is used for escaping.
+//
+// For example, the following string:
+//
+//     a b:"c d" 'e''f'  "g\""
+//
+// Would be parsed as:
+//
+//     []string{"a", "b:c d", "ef", `g"`}
+//
+// [copied from src/go/build/build.go]
+func splitQuoted(s string) (r []string, err error) {
+	var args []string
+	arg := make([]rune, len(s))
+	escaped := false
+	quoted := false
+	quote := '\x00'
+	i := 0
+	for _, rune := range s {
+		switch {
+		case escaped:
+			escaped = false
+		case rune == '\\':
+			escaped = true
+			continue
+		case quote != '\x00':
+			if rune == quote {
+				quote = '\x00'
+				continue
+			}
+		case rune == '"' || rune == '\'':
+			quoted = true
+			quote = rune
+			continue
+		case unicode.IsSpace(rune):
+			if quoted || i > 0 {
+				quoted = false
+				args = append(args, string(arg[:i]))
+				i = 0
+			}
+			continue
+		}
+		arg[i] = rune
+		i++
+	}
+	if quoted || i > 0 {
+		args = append(args, string(arg[:i]))
+	}
+	if quote != 0 {
+		err = errors.New("unclosed quote")
+	} else if escaped {
+		err = errors.New("unfinished escaping")
+	}
+	return args, err
 }