This CL adds an automatic, limited "go vet" to "go test".
If the building of a test package fails, vet is not run.
If vet fails, the test is not run.
The goal is that users don't notice vet as part of the "go test"
process at all, until vet speaks up and says something important.
This should help users find real problems in their code faster
(vet can just point to them instead of needing to debug a
test failure) and expands the scope of what kinds of things
vet can help with.
The "go vet" runs in parallel with the linking of the test binary,
so for incremental builds it typically does not slow the overall
"go test" at all: there's spare machine capacity during the link.
all.bash has less spare machine capacity. This CL increases
the time for all.bash on my laptop from 4m41s to 4m48s (+2.5%)
To opt out for a given run, use "go test -vet=off".
The vet checks used during "go test" are a subset of the full set,
restricted to ones that are 100% correct and therefore acceptable
to make mandatory. In this CL, that set is atomic, bool, buildtags,
nilfunc, and printf. Including printf is debatable, but I want to
include it for now and find out what needs to be scaled back.
(It already found one real problem in package os's tests that
previous go vet os had not turned up.)
Now that we can rely on type information it may be that printf
should make its function-name-based heuristic less aggressive
and have a whitelist of known print/printf functions.
Determining the exact set for Go 1.10 is #18085.
Running vet also means that programs now have to type-check
with both cmd/compile and go/types in order to pass "go test".
We don't start vet until cmd/compile has built the test package,
so normally the added go/types check doesn't find anything.
However, there is at least one instance where go/types is more
precise than cmd/compile: declared and not used errors involving
variables captured into closures.
This CL includes a printf fix to os/os_test.go and many declared
and not used fixes in the race detector tests.
Fixes #18084.
Change-Id: I353e00b9d1f9fec540c7557db5653e7501f5e1c9
Reviewed-on: https://go-review.googlesource.com/74356
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Reviewed-by: David Crawshaw <crawshaw@golang.org>
t.Errorf("%s has incorrect binding %v, want STB_LOCAL", hashbytes.Name, elf.ST_BIND(hashbytes.Info))
}
if f.Sections[hashbytes.Section] != note.section {
- t.Errorf("%s has incorrect section %v, want %s", hashbytes.Name, f.Sections[hashbytes.Section].Name, note.section)
+ t.Errorf("%s has incorrect section %v, want %s", hashbytes.Name, f.Sections[hashbytes.Section].Name, note.section.Name)
}
if hashbytes.Value-note.section.Addr != 16 {
t.Errorf("%s has incorrect offset into section %d, want 16", hashbytes.Name, hashbytes.Value-note.section.Addr)
// The go tool will ignore a directory named "testdata", making it available
// to hold ancillary data needed by the tests.
//
+// As part of building a test binary, go test runs go vet on the package
+// and its test source files to identify significant problems. If go vet
+// finds any problems, go test reports those and does not run the test binary.
+// Only a high-confidence subset of the default go vet checks are used.
+// To disable the running of go vet, use the -vet=off flag.
+//
+//
// Go test runs in two different modes: local directory mode when invoked with
// no package arguments (for example, 'go test'), and package list mode when
// invoked with package arguments (for example 'go test math', 'go test ./...',
// Verbose output: log all tests as they are run. Also print all
// text from Log and Logf calls even if the test succeeds.
//
+// -vet mode
+// Configure the invocation of "go vet" during "go test".
+// The default is to run "go vet". If mode is "off", vet is disabled.
+//
// The following flags are also recognized by 'go test' and can be used to
// profile the tests during execution:
//
}
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
tg.makeTempdir()
tg.setenv("GOPATH", tg.tempdir)
tg.setenv("GOCACHE", filepath.Join(tg.tempdir, "cache"))
tg.grepStderr(`([\\/]link|gccgo).*t4\.test`, "did not relink t4_test")
tg.grepStdout(`ok \tt/t4\t\(cached\)`, "did not cache t/t4")
}
+
+func TestTestVet(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+
+ tg.tempFile("p1_test.go", `
+ package p
+ import "testing"
+ func Test(t *testing.T) {
+ t.Logf("%d") // oops
+ }
+ `)
+
+ tg.runFail("test", filepath.Join(tg.tempdir, "p1_test.go"))
+ tg.grepStderr(`Logf format %d`, "did not diagnose bad Logf")
+ tg.run("test", "-vet=off", filepath.Join(tg.tempdir, "p1_test.go"))
+ tg.grepStdout(`^ok`, "did not print test summary")
+
+ tg.tempFile("p1.go", `
+ package p
+ import "fmt"
+ func F() {
+ fmt.Printf("%d") // oops
+ }
+ `)
+ tg.runFail("test", filepath.Join(tg.tempdir, "p1.go"))
+ tg.grepStderr(`Printf format %d`, "did not diagnose bad Printf")
+ tg.run("test", "-x", "-vet=shift", filepath.Join(tg.tempdir, "p1.go"))
+ tg.grepStderr(`[\\/]vet.*-shift`, "did not run vet with -shift")
+ tg.grepStdout(`\[no test files\]`, "did not print test summary")
+ tg.run("test", "-vet=off", filepath.Join(tg.tempdir, "p1.go"))
+ tg.grepStdout(`\[no test files\]`, "did not print test summary")
+}
The go tool will ignore a directory named "testdata", making it available
to hold ancillary data needed by the tests.
+As part of building a test binary, go test runs go vet on the package
+and its test source files to identify significant problems. If go vet
+finds any problems, go test reports those and does not run the test binary.
+Only a high-confidence subset of the default go vet checks are used.
+To disable the running of go vet, use the -vet=off flag.
+
Go test runs in two different modes: local directory mode when invoked with
no package arguments (for example, 'go test'), and package list mode when
invoked with package arguments (for example 'go test math', 'go test ./...',
Verbose output: log all tests as they are run. Also print all
text from Log and Logf calls even if the test succeeds.
+ -vet list
+ Configure the invocation of "go vet" during "go test"
+ to use the comma-separated list of vet checks.
+ If list is empty, "go test" runs "go vet" with a curated list of
+ checks believed to be always worth addressing.
+ If list is "off", "go test" does not run "go vet" at all.
+
The following flags are also recognized by 'go test' and can be used to
profile the tests during execution:
testArgs []string
testBench bool
testList bool
- testShowPass bool // show passing output
+ testShowPass bool // show passing output
+ testVetList string // -vet flag
pkgArgs []string
pkgs []*load.Package
"testing/internal/testdeps",
}
+// testVetFlags is the list of flags to pass to vet when invoked automatically during go test.
+var testVetFlags = []string{
+ // TODO(rsc): Decide which tests are enabled by default.
+ // See golang.org/issue/18085.
+ // "-asmdecl",
+ // "-assign",
+ "-atomic",
+ "-bool",
+ "-buildtags",
+ // "-cgocall",
+ // "-composites",
+ // "-copylocks",
+ // "-httpresponse",
+ // "-lostcancel",
+ // "-methods",
+ "-nilfunc",
+ "-printf",
+ // "-rangeloops",
+ // "-shift",
+ // "-structtags",
+ // "-tests",
+ // "-unreachable",
+ // "-unsafeptr",
+ // "-unusedresult",
+}
+
func runTest(cmd *base.Command, args []string) {
pkgArgs, testArgs = testFlags(args)
work.InstrumentInit()
work.BuildModeInit()
+ work.VetFlags = testVetFlags
+
pkgs = load.PackagesForBuild(pkgArgs)
if len(pkgs) == 0 {
base.Fatalf("no packages to test")
if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
build := b.CompileAction(work.ModeBuild, work.ModeBuild, p)
run := &work.Action{Mode: "test run", Package: p, Deps: []*work.Action{build}}
+ addTestVet(b, p, run, nil)
print := &work.Action{Mode: "test print", Func: builderNoTest, Package: p, Deps: []*work.Action{run}}
return build, run, print, nil
}
var imports, ximports []*load.Package
var stk load.ImportStack
stk.Push(p.ImportPath + " (test)")
+ rawTestImports := str.StringList(p.TestImports)
for i, path := range p.TestImports {
p1 := load.LoadImport(path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], load.UseVendor)
if p1.Error != nil {
stk.Pop()
stk.Push(p.ImportPath + "_test")
pxtestNeedsPtest := false
+ rawXTestImports := str.StringList(p.XTestImports)
for i, path := range p.XTestImports {
p1 := load.LoadImport(path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], load.UseVendor)
if p1.Error != nil {
ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...)
ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...)
ptest.Target = ""
- ptest.Imports = str.StringList(p.Imports, p.TestImports)
- ptest.Internal.Imports = append(append([]*load.Package{}, p.Internal.Imports...), imports...)
+ // Note: The preparation of the vet config requires that common
+ // indexes in ptest.Imports, ptest.Internal.Imports, and ptest.Internal.RawImports
+ // all line up (but RawImports can be shorter than the others).
+ // That is, for 0 ≤ i < len(RawImports),
+ // RawImports[i] is the import string in the program text,
+ // Imports[i] is the expanded import string (vendoring applied or relative path expanded away),
+ // and Internal.Imports[i] is the corresponding *Package.
+ // Any implicitly added imports appear in Imports and Internal.Imports
+ // but not RawImports (because they were not in the source code).
+ // We insert TestImports, imports, and rawTestImports at the start of
+ // these lists to preserve the alignment.
+ ptest.Imports = str.StringList(p.TestImports, p.Imports)
+ ptest.Internal.Imports = append(imports, p.Internal.Imports...)
+ ptest.Internal.RawImports = str.StringList(rawTestImports, p.Internal.RawImports)
ptest.Internal.ForceLibrary = true
ptest.Internal.Build = new(build.Package)
*ptest.Internal.Build = *p.Internal.Build
Build: &build.Package{
ImportPos: p.Internal.Build.XTestImportPos,
},
- Imports: ximports,
+ Imports: ximports,
+ RawImports: rawXTestImports,
},
}
if pxtestNeedsPtest {
}
}
buildAction = a
+ var installAction *work.Action
if testC || testNeedBinary {
// -c or profiling flag: create action to copy binary to ./test.out.
}
}
pmain.Target = target
- buildAction = &work.Action{
+ installAction = &work.Action{
Mode: "test build",
Func: work.BuildInstallFunc,
Deps: []*work.Action{buildAction},
Package: pmain,
Target: target,
}
- runAction = buildAction // make sure runAction != nil even if not running test
+ buildAction = installAction
+ runAction = installAction // make sure runAction != nil even if not running test
}
if testC {
printAction = &work.Action{Mode: "test print (nop)", Package: p, Deps: []*work.Action{runAction}} // nop
IgnoreFail: true,
TryCache: c.tryCache,
}
+ if len(ptest.GoFiles)+len(ptest.CgoFiles) > 0 {
+ addTestVet(b, ptest, runAction, installAction)
+ }
+ if pxtest != nil {
+ addTestVet(b, pxtest, runAction, installAction)
+ }
cleanAction := &work.Action{
Mode: "test clean",
Func: builderCleanTest,
return buildAction, runAction, printAction, nil
}
+func addTestVet(b *work.Builder, p *load.Package, runAction, installAction *work.Action) {
+ if testVetList == "off" {
+ return
+ }
+
+ vet := b.VetAction(work.ModeBuild, work.ModeBuild, p)
+ runAction.Deps = append(runAction.Deps, vet)
+ // Install will clean the build directory.
+ // Make sure vet runs first.
+ // The install ordering in b.VetAction does not apply here
+ // because we are using a custom installAction (created above).
+ if installAction != nil {
+ installAction.Deps = append(installAction.Deps, vet)
+ }
+}
+
func testImportStack(top string, p *load.Package, target string) []string {
stk := []string{top, p.ImportPath}
Search:
{Name: "covermode"},
{Name: "coverpkg"},
{Name: "exec"},
+ {Name: "vet"},
// Passed to 6.out, adding a "test." prefix to the name if necessary: -v becomes -test.v.
{Name: "bench", PassToTest: true},
testCover = true
case "outputdir":
outputDir = value
+ case "vet":
+ testVetList = value
}
}
if extraWord {
}
}
+ if testVetList != "" && testVetList != "off" {
+ if strings.Contains(testVetList, "=") {
+ base.Fatalf("-vet argument cannot contain equal signs")
+ }
+ if strings.Contains(testVetList, " ") {
+ base.Fatalf("-vet argument is comma-separated list, cannot contain spaces")
+ }
+ list := strings.Split(testVetList, ",")
+ for i, arg := range list {
+ list[i] = "-" + arg
+ }
+ testVetFlags = list
+ }
+
if cfg.BuildRace && testCoverMode != "atomic" {
base.Fatalf(`-covermode must be "atomic", not %q, when -race is enabled`, testCoverMode)
}
}()
x = 3
<-c
+ _ = x
}
}
}()
x = 3
<-c
+ _ = x
}
}
pkg.path = astFiles[0].Name.Name
pkg.files = files
// Type check the package.
- err := pkg.check(fs, astFiles)
- if err != nil {
- // Note that we only report this error when *verbose.
- Println(err)
- if mustTypecheck {
- errorf("%v", err)
+ errs := pkg.check(fs, astFiles)
+ if errs != nil {
+ if *verbose || mustTypecheck {
+ for _, err := range errs {
+ fmt.Fprintf(os.Stderr, "%v\n", err)
+ }
+ if mustTypecheck {
+ // This message could be silenced, and we could just exit,
+ // but it might be helpful at least at first to make clear that the
+ // above errors are coming from vet and not the compiler
+ // (they often look like compiler errors, such as "declared but not used").
+ errorf("typecheck failures")
+ }
}
}
return nil
}
-func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) error {
+func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) []error {
if stdImporter == nil {
if *source {
stdImporter = importer.For("source", nil)
pkg.selectors = make(map[*ast.SelectorExpr]*types.Selection)
pkg.spans = make(map[types.Object]Span)
pkg.types = make(map[ast.Expr]types.TypeAndValue)
+
+ var allErrors []error
config := types.Config{
// We use the same importer for all imports to ensure that
// everybody sees identical packages for the given paths.
Importer: stdImporter,
// By providing a Config with our own error function, it will continue
- // past the first error. There is no need for that function to do anything.
- Error: func(error) {},
+ // past the first error. We collect them all for printing later.
+ Error: func(e error) {
+ allErrors = append(allErrors, e)
+ },
Sizes: archSizes,
}
Uses: pkg.uses,
}
typesPkg, err := config.Check(pkg.path, fs, astFiles, info)
+ if len(allErrors) == 0 && err != nil {
+ allErrors = append(allErrors, err)
+ }
pkg.typesPkg = typesPkg
// update spans
for id, obj := range pkg.defs {
for id, obj := range pkg.uses {
pkg.growSpan(id, obj)
}
- return err
+ return allErrors
}
// matchArgType reports an error if printf verb t is not appropriate
// the contents are accessed; also, it is set
// whenever mtime is set.
case "netbsd":
- t.Logf("AccessTime didn't go backwards; was=%d, after=%d (Ignoring. See NetBSD issue golang.org/issue/19293)", at, pat)
+ t.Logf("AccessTime didn't go backwards; was=%v, after=%v (Ignoring. See NetBSD issue golang.org/issue/19293)", at, pat)
default:
- t.Errorf("AccessTime didn't go backwards; was=%d, after=%d", at, pat)
+ t.Errorf("AccessTime didn't go backwards; was=%v, after=%v", at, pat)
}
}
func TestFail(t *testing.T) {
done := make(chan bool)
x := 0
+ _ = x
go func() {
x = 42
done <- true
`, `
==================
--- FAIL: TestFail \(0...s\)
-.*main_test.go:13: true
+.*main_test.go:14: true
.*testing.go:.*: race detected during execution of test
FAIL`},
func TestFail(t *testing.T) {
done := make(chan bool)
x := 0
+ _ = x
go func() {
x = 42
done <- true
func TestNoRaceAtomicAddInt64(t *testing.T) {
var x1, x2 int8
+ _ = x1 + x2
var s int64
ch := make(chan bool, 2)
go func() {
func TestRaceAtomicAddInt64(t *testing.T) {
var x1, x2 int8
+ _ = x1 + x2
var s int64
ch := make(chan bool, 2)
go func() {
func TestNoRaceAtomicAddInt32(t *testing.T) {
var x1, x2 int8
+ _ = x1 + x2
var s int32
ch := make(chan bool, 2)
go func() {
func TestNoRaceAtomicLoadAddInt32(t *testing.T) {
var x int64
+ _ = x
var s int32
go func() {
x = 2
func TestNoRaceAtomicLoadStoreInt32(t *testing.T) {
var x int64
+ _ = x
var s int32
go func() {
x = 2
func TestNoRaceAtomicStoreCASInt32(t *testing.T) {
var x int64
+ _ = x
var s int32
go func() {
x = 2
func TestNoRaceAtomicCASLoadInt32(t *testing.T) {
var x int64
+ _ = x
var s int32
go func() {
x = 2
func TestNoRaceAtomicCASCASInt32(t *testing.T) {
var x int64
+ _ = x
var s int32
go func() {
x = 2
func TestNoRaceAtomicCASCASInt32_2(t *testing.T) {
var x1, x2 int8
+ _ = x1 + x2
var s int32
ch := make(chan bool, 2)
go func() {
func TestNoRaceAtomicLoadInt64(t *testing.T) {
var x int32
+ _ = x
var s int64
go func() {
x = 2
func TestNoRaceAtomicCASCASUInt64(t *testing.T) {
var x int64
+ _ = x
var s uint64
go func() {
x = 2
func TestNoRaceAtomicLoadStorePointer(t *testing.T) {
var x int64
+ _ = x
var s unsafe.Pointer
var y int = 2
var p unsafe.Pointer = unsafe.Pointer(&y)
func TestNoRaceAtomicStoreCASUint64(t *testing.T) {
var x int64
+ _ = x
var s uint64
go func() {
x = 2
func TestNoRaceChanSync(t *testing.T) {
v := 0
+ _ = v
c := make(chan int)
go func() {
v = 1
func TestNoRaceChanSyncRev(t *testing.T) {
v := 0
+ _ = v
c := make(chan int)
go func() {
c <- 0
func TestNoRaceChanAsync(t *testing.T) {
v := 0
+ _ = v
c := make(chan int, 10)
go func() {
v = 1
func TestRaceChanAsyncRev(t *testing.T) {
v := 0
+ _ = v
c := make(chan int, 10)
go func() {
c <- 0
func TestNoRaceChanAsyncCloseRecv(t *testing.T) {
v := 0
+ _ = v
c := make(chan int, 10)
go func() {
v = 1
func TestNoRaceChanAsyncCloseRecv2(t *testing.T) {
v := 0
+ _ = v
c := make(chan int, 10)
go func() {
v = 1
func TestNoRaceChanAsyncCloseRecv3(t *testing.T) {
v := 0
+ _ = v
c := make(chan int, 10)
go func() {
v = 1
func TestNoRaceChanSyncCloseRecv(t *testing.T) {
v := 0
+ _ = v
c := make(chan int)
go func() {
v = 1
func TestNoRaceChanSyncCloseRecv2(t *testing.T) {
v := 0
+ _ = v
c := make(chan int)
go func() {
v = 1
func TestNoRaceChanSyncCloseRecv3(t *testing.T) {
v := 0
+ _ = v
c := make(chan int)
go func() {
v = 1
func TestRaceChanSyncCloseSend(t *testing.T) {
v := 0
+ _ = v
c := make(chan int)
go func() {
v = 1
func TestRaceChanAsyncCloseSend(t *testing.T) {
v := 0
+ _ = v
c := make(chan int, 10)
go func() {
v = 1
compl := make(chan bool, 2)
v1 := 0
v2 := 0
+ _ = v1 + v2
c := make(chan int)
go func() {
defer func() {
func TestRaceChanSendLen(t *testing.T) {
v := 0
+ _ = v
c := make(chan int, 10)
go func() {
v = 1
func TestRaceChanRecvLen(t *testing.T) {
v := 0
+ _ = v
c := make(chan int, 10)
c <- 1
go func() {
compl := make(chan bool, 2)
v1 := 0
v2 := 0
+ _ = v1 + v2
c := make(chan int, 1)
go func() {
v1 = 1
func TestRaceChanWrongSend(t *testing.T) {
v1 := 0
v2 := 0
+ _ = v1 + v2
c := make(chan int, 2)
go func() {
v1 = 1
func TestRaceChanWrongClose(t *testing.T) {
v1 := 0
v2 := 0
+ _ = v1 + v2
c := make(chan int, 1)
done := make(chan bool)
go func() {
func TestRaceChanCloseLen(t *testing.T) {
v := 0
+ _ = v
c := make(chan int, 10)
c <- 0
go func() {
done := make(chan struct{})
mtx := make(chan struct{}, 1)
data := 0
+ _ = data
go func() {
mtx <- struct{}{}
data = 42
mtx := make(chan struct{}, 1)
aux := make(chan bool)
data := 0
+ _ = data
go func() {
select {
case mtx <- struct{}{}:
done := make(chan struct{})
mtx := make(chan bool, 2)
data := 0
+ _ = data
go func() {
mtx <- true
data = 42
func TestRaceFin(t *testing.T) {
c := make(chan bool)
y := 0
+ _ = y
go func() {
x := new(string)
runtime.SetFinalizer(x, func(x *string) {
func TestRaceMapVariable(t *testing.T) {
ch := make(chan bool, 1)
m := make(map[int]int)
+ _ = m
go func() {
m = make(map[int]int)
ch <- true
conns[1] = []int{0}
ch := make(chan bool, 1)
var err error
+ _ = err
go func() {
conns[1][0], err = connect()
ch <- true
func TestRaceIntRWClosures(t *testing.T) {
var x, y int
+ _ = y
ch := make(chan int, 2)
go func() {
func TestNoRaceIntRWClosures(t *testing.T) {
var x, y int
+ _ = y
ch := make(chan int, 1)
go func() {
func TestRaceInt32RWClosures(t *testing.T) {
var x, y int32
+ _ = y
ch := make(chan bool, 2)
go func() {
func TestRaceCaseBody(t *testing.T) {
var x, y int
+ _ = y
ch := make(chan int, 2)
go func() {
func TestNoRaceCaseFallthrough(t *testing.T) {
var x, y, z int
+ _ = y
ch := make(chan int, 2)
z = 1
func TestRaceCaseFallthrough(t *testing.T) {
var x, y, z int
+ _ = y
ch := make(chan int, 2)
z = 1
const N = 2
var a [N]int
var x, y int
+ _ = x + y
done := make(chan bool, N)
for i, v := range a {
go func(i int) {
func TestRacePlus(t *testing.T) {
var x, y, z int
+ _ = y
ch := make(chan int, 2)
go func() {
func TestRacePlus2(t *testing.T) {
var x, y, z int
+ _ = y
ch := make(chan int, 2)
go func() {
func TestNoRacePlus(t *testing.T) {
var x, y, z, f int
+ _ = x + y + f
ch := make(chan int, 2)
go func() {
func TestRaceComplement(t *testing.T) {
var x, y, z int
+ _ = x
ch := make(chan int, 2)
go func() {
func TestRaceDiv(t *testing.T) {
var x, y, z int
+ _ = x
ch := make(chan int, 2)
go func() {
func TestRaceDivConst(t *testing.T) {
var x, y, z uint32
+ _ = x
ch := make(chan int, 2)
go func() {
func TestRaceMod(t *testing.T) {
var x, y, z int
+ _ = x
ch := make(chan int, 2)
go func() {
func TestRaceModConst(t *testing.T) {
var x, y, z int
+ _ = x
ch := make(chan int, 2)
go func() {
func TestRaceRotate(t *testing.T) {
var x, y, z uint32
+ _ = x
ch := make(chan int, 2)
go func() {
func TestRaceFuncVariableWW(t *testing.T) {
var f func(x int) int
+ _ = f
ch := make(chan bool, 1)
go func() {
f = func(x int) int {
// This one should not belong to mop_test
func TestRacePanic(t *testing.T) {
var x int
+ _ = x
var zero int = 0
ch := make(chan bool, 2)
go func() {
ch := make(chan bool, 1)
var mu sync.Mutex
x := 0
+ _ = x
go func() {
mu.Lock()
x = 42
c := make(chan bool, 1)
var mu sync.Mutex
x := 0
+ _ = x
go func() {
x = func() int { // Write of x must be under the mutex.
mu.Lock()
const P = 4
const N = 1e6
var tinySink *byte
+ _ = tinySink
done := make(chan bool)
for p := 0; p < P; p++ {
go func() {
func TestNoRaceMutex(t *testing.T) {
var mu sync.Mutex
var x int16 = 0
+ _ = x
ch := make(chan bool, 2)
go func() {
mu.Lock()
func TestRaceMutex(t *testing.T) {
var mu sync.Mutex
var x int16 = 0
+ _ = x
ch := make(chan bool, 2)
go func() {
x = 1
var mu1 sync.Mutex
var mu2 sync.Mutex
var x int8 = 0
+ _ = x
ch := make(chan bool, 2)
go func() {
mu1.Lock()
func TestNoRaceMutexPureHappensBefore(t *testing.T) {
var mu sync.Mutex
var x int16 = 0
+ _ = x
ch := make(chan bool, 2)
go func() {
x = 1
var mu sync.Mutex
ch := make(chan bool, 2)
x := 0
+ _ = x
mu.Lock()
go func() {
x = 1
var mu1 sync.Mutex
var mu2 sync.RWMutex
var x int16 = 0
+ _ = x
ch := make(chan bool, 2)
go func() {
mu1.Lock()
func TestNoRaceRWMutex(t *testing.T) {
var mu sync.RWMutex
var x, y int64 = 0, 1
+ _ = y
ch := make(chan bool, 2)
go func() {
mu.Lock()
func TestNoRaceSelect1(t *testing.T) {
var x int
+ _ = x
compl := make(chan bool)
c := make(chan bool)
c1 := make(chan bool)
func TestNoRaceSelect2(t *testing.T) {
var x int
+ _ = x
compl := make(chan bool)
c := make(chan bool)
c1 := make(chan bool)
func TestNoRaceSelect3(t *testing.T) {
var x int
+ _ = x
compl := make(chan bool)
c := make(chan bool, 10)
c1 := make(chan bool)
func TestNoRaceSelect5(t *testing.T) {
test := func(sel, needSched bool) {
var x int
+ _ = x
ch := make(chan bool)
c1 := make(chan bool)
func TestRaceSelect1(t *testing.T) {
var x int
+ _ = x
compl := make(chan bool, 2)
c := make(chan bool)
c1 := make(chan bool)
func TestRaceSelect2(t *testing.T) {
var x int
+ _ = x
compl := make(chan bool)
c := make(chan bool)
c1 := make(chan bool)
func TestRaceSelect3(t *testing.T) {
var x int
+ _ = x
compl := make(chan bool)
c := make(chan bool)
c1 := make(chan bool)
func TestNoRaceCond(t *testing.T) {
x := 0
+ _ = x
condition := 0
var mu sync.Mutex
cond := sync.NewCond(&mu)
var mu sync.Mutex
cond := sync.NewCond(&mu)
x := 0
+ _ = x
condition := 0
go func() {
time.Sleep(10 * time.Millisecond) // Enter cond.Wait loop
allDone := make(chan bool, N)
var x int
+ _ = x
var f, g, h func()
f = func() {
func TestNoRaceAfterFunc3(t *testing.T) {
c := make(chan bool, 1)
x := 0
+ _ = x
time.AfterFunc(1e7, func() {
x = 1
c <- true
func TestRaceAfterFunc3(t *testing.T) {
c := make(chan bool, 2)
x := 0
+ _ = x
time.AfterFunc(1e7, func() {
x = 1
c <- true
// comprehensible.
func TestRaceGoroutineCreationStack(t *testing.T) {
var x int
+ _ = x
var ch = make(chan bool, 1)
f1 := func() {
func TestNoRaceWaitGroup(t *testing.T) {
var x int
+ _ = x
var wg sync.WaitGroup
n := 1
for i := 0; i < n; i++ {
func TestRaceWaitGroup(t *testing.T) {
var x int
+ _ = x
var wg sync.WaitGroup
n := 2
for i := 0; i < n; i++ {
func TestNoRaceWaitGroup2(t *testing.T) {
var x int
+ _ = x
var wg sync.WaitGroup
wg.Add(1)
go func() {
// incrementing counter in Add and locking wg's mutex
func TestRaceWaitGroupAsMutex(t *testing.T) {
var x int
+ _ = x
var wg sync.WaitGroup
c := make(chan bool, 2)
go func() {
func TestRaceWaitGroupWrongWait(t *testing.T) {
c := make(chan bool, 2)
var x int
+ _ = x
var wg sync.WaitGroup
go func() {
wg.Add(1)
// Correct usage but still a race
func TestRaceWaitGroup2(t *testing.T) {
var x int
+ _ = x
var wg sync.WaitGroup
wg.Add(2)
go func() {
func TestNoRaceWaitGroupPanicRecover(t *testing.T) {
var x int
+ _ = x
var wg sync.WaitGroup
defer func() {
err := recover()
// Is it possible to get a race by synchronization via panic?
func TestNoRaceWaitGroupPanicRecover2(t *testing.T) {
var x int
+ _ = x
var wg sync.WaitGroup
ch := make(chan bool, 1)
var f func() = func() {