| | |
| | |
| | |
| |
|
| | package loopvar_test |
| |
|
| | import ( |
| | "internal/testenv" |
| | "os/exec" |
| | "path/filepath" |
| | "regexp" |
| | "runtime" |
| | "strings" |
| | "testing" |
| | ) |
| |
|
| | type testcase struct { |
| | lvFlag string |
| | buildExpect string |
| | expectRC int |
| | files []string |
| | } |
| |
|
| | var for_files = []string{ |
| | "for_esc_address.go", |
| | "for_esc_closure.go", |
| | "for_esc_minimal_closure.go", |
| | "for_esc_method.go", |
| | "for_complicated_esc_address.go", |
| | } |
| |
|
| | var range_files = []string{ |
| | "range_esc_address.go", |
| | "range_esc_closure.go", |
| | "range_esc_minimal_closure.go", |
| | "range_esc_method.go", |
| | } |
| |
|
| | var cases = []testcase{ |
| | {"-1", "", 11, for_files[:1]}, |
| | {"0", "", 0, for_files[:1]}, |
| | {"1", "", 0, for_files[:1]}, |
| | {"2", "loop variable i now per-iteration,", 0, for_files}, |
| |
|
| | {"-1", "", 11, range_files[:1]}, |
| | {"0", "", 0, range_files[:1]}, |
| | {"1", "", 0, range_files[:1]}, |
| | {"2", "loop variable i now per-iteration,", 0, range_files}, |
| |
|
| | {"1", "", 0, []string{"for_nested.go"}}, |
| | } |
| |
|
| | |
| | func TestLoopVarGo1_21(t *testing.T) { |
| | switch runtime.GOOS { |
| | case "linux", "darwin": |
| | default: |
| | t.Skipf("Slow test, usually avoid it, os=%s not linux or darwin", runtime.GOOS) |
| | } |
| | switch runtime.GOARCH { |
| | case "amd64", "arm64": |
| | default: |
| | t.Skipf("Slow test, usually avoid it, arch=%s not amd64 or arm64", runtime.GOARCH) |
| | } |
| |
|
| | testenv.MustHaveGoBuild(t) |
| | gocmd := testenv.GoToolPath(t) |
| | tmpdir := t.TempDir() |
| | output := filepath.Join(tmpdir, "foo.exe") |
| |
|
| | for i, tc := range cases { |
| | for _, f := range tc.files { |
| | source := f |
| | cmd := testenv.Command(t, gocmd, "build", "-o", output, "-gcflags=-lang=go1.21 -d=loopvar="+tc.lvFlag, source) |
| | cmd.Env = append(cmd.Env, "GOEXPERIMENT=loopvar", "HOME="+tmpdir) |
| | cmd.Dir = "testdata" |
| | t.Logf("File %s loopvar=%s expect '%s' exit code %d", f, tc.lvFlag, tc.buildExpect, tc.expectRC) |
| | b, e := cmd.CombinedOutput() |
| | if e != nil { |
| | t.Error(e) |
| | } |
| | if tc.buildExpect != "" { |
| | s := string(b) |
| | if !strings.Contains(s, tc.buildExpect) { |
| | t.Errorf("File %s test %d expected to match '%s' with \n-----\n%s\n-----", f, i, tc.buildExpect, s) |
| | } |
| | } |
| | |
| | cmd = testenv.Command(t, output) |
| | b, e = cmd.CombinedOutput() |
| | if tc.expectRC != 0 { |
| | if e == nil { |
| | t.Errorf("Missing expected error, file %s, case %d", f, i) |
| | } else if ee, ok := (e).(*exec.ExitError); !ok || ee.ExitCode() != tc.expectRC { |
| | t.Error(e) |
| | } else { |
| | |
| | } |
| | } else if e != nil { |
| | t.Error(e) |
| | } |
| | } |
| | } |
| | } |
| |
|
| | func TestLoopVarInlinesGo1_21(t *testing.T) { |
| | switch runtime.GOOS { |
| | case "linux", "darwin": |
| | default: |
| | t.Skipf("Slow test, usually avoid it, os=%s not linux or darwin", runtime.GOOS) |
| | } |
| | switch runtime.GOARCH { |
| | case "amd64", "arm64": |
| | default: |
| | t.Skipf("Slow test, usually avoid it, arch=%s not amd64 or arm64", runtime.GOARCH) |
| | } |
| |
|
| | testenv.MustHaveGoBuild(t) |
| | gocmd := testenv.GoToolPath(t) |
| | tmpdir := t.TempDir() |
| |
|
| | root := "cmd/compile/internal/loopvar/testdata/inlines" |
| |
|
| | f := func(pkg string) string { |
| | |
| | |
| | |
| | cmd := testenv.Command(t, gocmd, "run", "-gcflags="+root+"/...=-lang=go1.21", "-gcflags="+pkg+"=-d=loopvar=1", root) |
| | cmd.Env = append(cmd.Env, "GOEXPERIMENT=noloopvar", "HOME="+tmpdir) |
| | cmd.Dir = filepath.Join("testdata", "inlines") |
| |
|
| | b, e := cmd.CombinedOutput() |
| | if e != nil { |
| | t.Error(e) |
| | } |
| | return string(b) |
| | } |
| |
|
| | a := f(root + "/a") |
| | b := f(root + "/b") |
| | c := f(root + "/c") |
| | m := f(root) |
| |
|
| | t.Log(a) |
| | t.Log(b) |
| | t.Log(c) |
| | t.Log(m) |
| |
|
| | if !strings.Contains(a, "f, af, bf, abf, cf sums = 100, 45, 100, 100, 100") { |
| | t.Errorf("Did not see expected value of a") |
| | } |
| | if !strings.Contains(b, "f, af, bf, abf, cf sums = 100, 100, 45, 45, 100") { |
| | t.Errorf("Did not see expected value of b") |
| | } |
| | if !strings.Contains(c, "f, af, bf, abf, cf sums = 100, 100, 100, 100, 45") { |
| | t.Errorf("Did not see expected value of c") |
| | } |
| | if !strings.Contains(m, "f, af, bf, abf, cf sums = 45, 100, 100, 100, 100") { |
| | t.Errorf("Did not see expected value of m") |
| | } |
| | } |
| |
|
| | func countMatches(s, re string) int { |
| | slice := regexp.MustCompile(re).FindAllString(s, -1) |
| | return len(slice) |
| | } |
| |
|
| | func TestLoopVarHashes(t *testing.T) { |
| | |
| | switch runtime.GOOS { |
| | case "linux", "darwin": |
| | default: |
| | t.Skipf("Slow test, usually avoid it, os=%s not linux or darwin", runtime.GOOS) |
| | } |
| | switch runtime.GOARCH { |
| | case "amd64", "arm64": |
| | default: |
| | t.Skipf("Slow test, usually avoid it, arch=%s not amd64 or arm64", runtime.GOARCH) |
| | } |
| |
|
| | testenv.MustHaveGoBuild(t) |
| | gocmd := testenv.GoToolPath(t) |
| | tmpdir := t.TempDir() |
| |
|
| | root := "cmd/compile/internal/loopvar/testdata/inlines" |
| |
|
| | f := func(hash string) string { |
| | |
| | |
| | |
| | |
| | cmd := testenv.Command(t, gocmd, "run", "-trimpath", root) |
| | cmd.Env = append(cmd.Env, "GOCOMPILEDEBUG=loopvarhash="+hash, "HOME="+tmpdir) |
| | cmd.Dir = filepath.Join("testdata", "inlines") |
| |
|
| | b, _ := cmd.CombinedOutput() |
| | |
| | return string(b) |
| | } |
| |
|
| | for _, arg := range []string{"v001100110110110010100100", "vx336ca4"} { |
| | m := f(arg) |
| | t.Log(m) |
| |
|
| | mCount := countMatches(m, "loopvarhash triggered cmd/compile/internal/loopvar/testdata/inlines/main.go:27:6: .* 001100110110110010100100") |
| | otherCount := strings.Count(m, "loopvarhash") |
| | if mCount < 1 { |
| | t.Errorf("%s: did not see triggered main.go:27:6", arg) |
| | } |
| | if mCount != otherCount { |
| | t.Errorf("%s: too many matches", arg) |
| | } |
| | mCount = countMatches(m, "cmd/compile/internal/loopvar/testdata/inlines/main.go:27:6: .* \\[bisect-match 0x7802e115b9336ca4\\]") |
| | otherCount = strings.Count(m, "[bisect-match ") |
| | if mCount < 1 { |
| | t.Errorf("%s: did not see bisect-match for main.go:27:6", arg) |
| | } |
| | if mCount != otherCount { |
| | t.Errorf("%s: too many matches", arg) |
| | } |
| |
|
| | |
| | if !strings.Contains(m, ", 100, 100, 100, 100") { |
| | t.Errorf("%s: did not see expected value of m run", arg) |
| | } |
| | } |
| | } |
| |
|
| | |
| | func TestLoopVarVersionEnableFlag(t *testing.T) { |
| | switch runtime.GOOS { |
| | case "linux", "darwin": |
| | default: |
| | t.Skipf("Slow test, usually avoid it, os=%s not linux or darwin", runtime.GOOS) |
| | } |
| | switch runtime.GOARCH { |
| | case "amd64", "arm64": |
| | default: |
| | t.Skipf("Slow test, usually avoid it, arch=%s not amd64 or arm64", runtime.GOARCH) |
| | } |
| |
|
| | testenv.MustHaveGoBuild(t) |
| | gocmd := testenv.GoToolPath(t) |
| |
|
| | |
| | cmd := testenv.Command(t, gocmd, "run", "-gcflags=-lang=go1.22 -d=loopvar=3", "opt.go") |
| | cmd.Dir = filepath.Join("testdata") |
| |
|
| | b, err := cmd.CombinedOutput() |
| | m := string(b) |
| |
|
| | t.Log(m) |
| |
|
| | yCount := strings.Count(m, "opt.go:16:6: loop variable private now per-iteration, heap-allocated (loop inlined into ./opt.go:29)") |
| | nCount := strings.Count(m, "shared") |
| |
|
| | if yCount != 1 { |
| | t.Errorf("yCount=%d != 1", yCount) |
| | } |
| | if nCount > 0 { |
| | t.Errorf("nCount=%d > 0", nCount) |
| | } |
| | if err != nil { |
| | t.Errorf("err=%v != nil", err) |
| | } |
| | } |
| |
|
| | |
| | func TestLoopVarVersionEnableGoBuild(t *testing.T) { |
| | switch runtime.GOOS { |
| | case "linux", "darwin": |
| | default: |
| | t.Skipf("Slow test, usually avoid it, os=%s not linux or darwin", runtime.GOOS) |
| | } |
| | switch runtime.GOARCH { |
| | case "amd64", "arm64": |
| | default: |
| | t.Skipf("Slow test, usually avoid it, arch=%s not amd64 or arm64", runtime.GOARCH) |
| | } |
| |
|
| | testenv.MustHaveGoBuild(t) |
| | gocmd := testenv.GoToolPath(t) |
| |
|
| | |
| | cmd := testenv.Command(t, gocmd, "run", "-gcflags=-lang=go1.21 -d=loopvar=3", "opt-122.go") |
| | cmd.Dir = filepath.Join("testdata") |
| |
|
| | b, err := cmd.CombinedOutput() |
| | m := string(b) |
| |
|
| | t.Log(m) |
| |
|
| | yCount := strings.Count(m, "opt-122.go:18:6: loop variable private now per-iteration, heap-allocated (loop inlined into ./opt-122.go:31)") |
| | nCount := strings.Count(m, "shared") |
| |
|
| | if yCount != 1 { |
| | t.Errorf("yCount=%d != 1", yCount) |
| | } |
| | if nCount > 0 { |
| | t.Errorf("nCount=%d > 0", nCount) |
| | } |
| | if err != nil { |
| | t.Errorf("err=%v != nil", err) |
| | } |
| | } |
| |
|
| | |
| | func TestLoopVarVersionDisableFlag(t *testing.T) { |
| | switch runtime.GOOS { |
| | case "linux", "darwin": |
| | default: |
| | t.Skipf("Slow test, usually avoid it, os=%s not linux or darwin", runtime.GOOS) |
| | } |
| | switch runtime.GOARCH { |
| | case "amd64", "arm64": |
| | default: |
| | t.Skipf("Slow test, usually avoid it, arch=%s not amd64 or arm64", runtime.GOARCH) |
| | } |
| |
|
| | testenv.MustHaveGoBuild(t) |
| | gocmd := testenv.GoToolPath(t) |
| |
|
| | |
| | cmd := testenv.Command(t, gocmd, "run", "-gcflags=-lang=go1.21 -d=loopvar=3", "opt.go") |
| | cmd.Dir = filepath.Join("testdata") |
| |
|
| | b, err := cmd.CombinedOutput() |
| | m := string(b) |
| |
|
| | t.Log(m) |
| |
|
| | yCount := strings.Count(m, "opt.go:16:6: loop variable private now per-iteration, heap-allocated (loop inlined into ./opt.go:29)") |
| | nCount := strings.Count(m, "shared") |
| |
|
| | if yCount != 0 { |
| | t.Errorf("yCount=%d != 0", yCount) |
| | } |
| | if nCount > 0 { |
| | t.Errorf("nCount=%d > 0", nCount) |
| | } |
| | if err == nil { |
| | t.Errorf("err=%v == nil", err) |
| | } |
| | } |
| |
|
| | |
| | func TestLoopVarVersionDisableGoBuild(t *testing.T) { |
| | switch runtime.GOOS { |
| | case "linux", "darwin": |
| | default: |
| | t.Skipf("Slow test, usually avoid it, os=%s not linux or darwin", runtime.GOOS) |
| | } |
| | switch runtime.GOARCH { |
| | case "amd64", "arm64": |
| | default: |
| | t.Skipf("Slow test, usually avoid it, arch=%s not amd64 or arm64", runtime.GOARCH) |
| | } |
| |
|
| | testenv.MustHaveGoBuild(t) |
| | gocmd := testenv.GoToolPath(t) |
| |
|
| | |
| | cmd := testenv.Command(t, gocmd, "run", "-gcflags=-lang=go1.22 -d=loopvar=3", "opt-121.go") |
| | cmd.Dir = filepath.Join("testdata") |
| |
|
| | b, err := cmd.CombinedOutput() |
| | m := string(b) |
| |
|
| | t.Log(m) |
| |
|
| | yCount := strings.Count(m, "opt-121.go:18:6: loop variable private now per-iteration, heap-allocated (loop inlined into ./opt-121.go:31)") |
| | nCount := strings.Count(m, "shared") |
| |
|
| | if yCount != 0 { |
| | t.Errorf("yCount=%d != 0", yCount) |
| | } |
| | if nCount > 0 { |
| | t.Errorf("nCount=%d > 0", nCount) |
| | } |
| | if err == nil { |
| | t.Errorf("err=%v == nil", err) |
| | } |
| | } |
| |
|