diff options
Diffstat (limited to 'test/run.go')
-rw-r--r-- | test/run.go | 581 |
1 files changed, 421 insertions, 160 deletions
diff --git a/test/run.go b/test/run.go index d7f5d02391..6296234d56 100644 --- a/test/run.go +++ b/test/run.go @@ -9,6 +9,7 @@ package main import ( "bytes" + "encoding/json" "errors" "flag" "fmt" @@ -42,11 +43,55 @@ var ( 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,") + + // Normal test runs should test with both -G=0 and -G=3 for types2 + // coverage. But the unified experiment always uses types2, so + // testing with -G=3 is redundant. + glevels := "0,3" + if enabled { + glevels = "0" + } + + 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 +101,13 @@ func defaultAllCodeGen() bool { } 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 +128,13 @@ const maxTests = 5000 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 +161,11 @@ func main() { } 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 +173,7 @@ func main() { } 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 +190,15 @@ func main() { 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 +206,8 @@ func main() { 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 +326,73 @@ type test struct { 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. It should only be called for tests known to use +// types2. +func (t *test) initExpectFail() { + if *force { + return } - if toRun == nil { - toRun = make(chan *test, maxTests) - go runTests() + + 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) } - select { - case toRun <- t: - default: - panic("toRun buffer size (maxTests) is too small") + + 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 + } } - return t +} + +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 @@ -480,12 +579,16 @@ func init() { checkShouldTest() } // 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 != 0 { + 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 == 0 } var errTimeout = errors.New("command exceeded time limit") @@ -541,7 +644,11 @@ func (t *test) run() { 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 +676,8 @@ func (t *test) run() { return } + goexp := env.GOEXPERIMENT + // collect flags for len(args) > 0 && strings.HasPrefix(args[0], "-") { switch args[0] { @@ -595,7 +704,11 @@ func (t *test) run() { } 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 +729,63 @@ func (t *test) run() { } } + 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 + } + } + + if hasGFlag && t.glevel != 0 { + // test provides explicit -G flag already; don't run again + if *verbose { + fmt.Printf("excl\t%s\n", t.goFileName()) + } + return false + } + + if t.glevel == 0 && !hasGFlag && !unifiedEnabled { + // tests should always pass when run w/o types2 (i.e., using the + // legacy typechecker). + return true + } + + t.initExpectFail() + + switch tool { + case Build, Run: + // ok; handled in goGcflags + + case Compile: + if !hasGFlag { + flags = append(flags, fmt.Sprintf("-G=%v", t.glevel)) + } + + default: + // 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 +862,10 @@ func (t *test) run() { 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 +920,10 @@ func (t *test) run() { 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 +952,20 @@ func (t *test) run() { 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 - } - } + case "compile": + if !validForGLevel(Compile) { + return } - // 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": // 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 +981,10 @@ func (t *test) run() { } 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 +1030,10 @@ func (t *test) run() { 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 +1092,10 @@ func (t *test) run() { } 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 +1121,7 @@ func (t *test) run() { return } - cmd := []string{goTool(), "run", goGcflags()} + cmd := []string{goTool(), "run", t.goGcflags()} if *linkshared { cmd = append(cmd, "-linkshared") } @@ -997,13 +1135,21 @@ func (t *test) run() { 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 +1229,14 @@ func (t *test) run() { } 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 +1258,17 @@ func (t *test) run() { 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 +1290,7 @@ func (t *test) run() { } 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 +1305,10 @@ func (t *test) run() { 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 +1316,7 @@ func (t *test) run() { <-rungatec }() runInDir = "" - cmd := []string{goTool(), "run", goGcflags()} + cmd := []string{goTool(), "run", t.goGcflags()} if *linkshared { cmd = append(cmd, "-linkshared") } @@ -1173,7 +1331,7 @@ func (t *test) run() { 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 +1344,14 @@ func (t *test) run() { 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") } @@ -1941,66 +2103,165 @@ func overlayDir(dstRoot, srcRoot string) error { }) } +// 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) - - "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/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 +var types2Failures = setOf( + "directive.go", // misplaced compiler directive checks + "float_lit3.go", // types2 reports extra errors + "import1.go", // types2 reports extra errors + "import6.go", // issue #43109 + "initializerr.go", // types2 reports extra errors + "linkname2.go", // error reported by noder (not running for types2 errorcheck test) + "notinheap.go", // types2 doesn't report errors about conversions that are invalid due to //go:notinheap + "shift1.go", // issue #42989 + "typecheck.go", // invalid function is not causing errors when called + + "interface/private.go", // types2 phrases errors differently (doesn't use non-spec "private" term) + + "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/bug374.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/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/issue16428.go", // types2 reports two instead of one error + "fixedbugs/issue17038.go", // types2 doesn't report a follow-on error (pref: types2) + "fixedbugs/issue17645.go", // multiple errors on same line + "fixedbugs/issue18331.go", // missing error about misuse of //go:noescape (irgen needs code from noder) + "fixedbugs/issue18419.go", // types2 reports + "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/issue42058a.go", // types2 doesn't report "channel element type too large" + "fixedbugs/issue42058b.go", // types2 doesn't report "channel element type too large" + "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/issue47201.go", // types2 spells the error message differently + "fixedbugs/issue5609.go", // types2 needs a better error message + "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) + "fixedbugs/bug385_32.go", // types2 doesn't produce missing error "type .* too large" (32-bit specific) +) + +var g3Failures = setOf( + "writebarrier.go", // correct diagnostics, but different lines (probably irgen's fault) + + "fixedbugs/issue30862.go", // -G=3 doesn't handle //go:nointerface + + "typeparam/nested.go", // -G=3 doesn't support function-local types with generics + + "typeparam/mdempsky/4.go", // -G=3 can't export functions with labeled breaks in loops + "typeparam/mdempsky/15.go", // ICE in (*irgen).buildClosure +) + +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 + + "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" +) + +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 } |