-13b25c25faa8afd625732d2630a4f9ece5cacb2e
+4164071703c531b5234b790b76df4931c37a8d9c
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
-594668a5a96267a46282ce3007a584ec07adf705
+5348aed83e39bd1d450d92d7f627e994c2db6ebf
The first line of this file holds the git revision number of the
last merge done from the master library sources.
Special cases
A few special C types which would normally be represented by a pointer
-type in Go are instead represented by a uintptr. Those types are
-the CF*Ref types from the CoreFoundation library on Darwin, including:
-
- CFAllocatorRef
- CFArrayRef
- CFAttributedStringRef
- CFBagRef
- CFBinaryHeapRef
- CFBitVectorRef
- CFBooleanRef
- CFBundleRef
- CFCalendarRef
- CFCharacterSetRef
- CFDataRef
- CFDateFormatterRef
- CFDateRef
- CFDictionaryRef
- CFErrorRef
- CFFileDescriptorRef
- CFFileSecurityRef
- CFLocaleRef
- CFMachPortRef
- CFMessagePortRef
- CFMutableArrayRef
- CFMutableAttributedStringRef
- CFMutableBagRef
- CFMutableBitVectorRef
- CFMutableCharacterSetRef
- CFMutableDataRef
- CFMutableDictionaryRef
- CFMutableSetRef
- CFMutableStringRef
- CFNotificationCenterRef
- CFNullRef
- CFNumberFormatterRef
- CFNumberRef
- CFPlugInInstanceRef
- CFPlugInRef
- CFPropertyListRef
- CFReadStreamRef
- CFRunLoopObserverRef
- CFRunLoopRef
- CFRunLoopSourceRef
- CFRunLoopTimerRef
- CFSetRef
- CFSocketRef
- CFStringRef
- CFStringTokenizerRef
- CFTimeZoneRef
- CFTreeRef
- CFTypeRef
- CFURLCreateFromFSRef
- CFURLEnumeratorRef
- CFURLGetFSRef
- CFURLRef
- CFUUIDRef
- CFUserNotificationRef
- CFWriteStreamRef
- CFXMLNodeRef
- CFXMLParserRef
- CFXMLTreeRef
-
-Also the object types from Java's JNI interface:
+type in Go are instead represented by a uintptr. Those include:
+
+1. The *Ref types on Darwin, rooted at CoreFoundation's CFTypeRef type.
+
+2. The object types from Java's JNI interface:
jobject
jclass
// Determine kinds for names we already know about,
// like #defines or 'struct foo', before bothering with gcc.
var names, needType []*Name
+ optional := map[*Name]bool{}
for _, key := range nameKeys(f.Name) {
n := f.Name[key]
// If we've already found this name as a #define
continue
}
+ if goos == "darwin" && strings.HasSuffix(n.C, "Ref") {
+ // For FooRef, find out if FooGetTypeID exists.
+ s := n.C[:len(n.C)-3] + "GetTypeID"
+ n := &Name{Go: s, C: s}
+ names = append(names, n)
+ optional[n] = true
+ }
+
// Otherwise, we'll need to find out from gcc.
names = append(names, n)
}
for i, n := range names {
switch sniff[i] {
default:
+ if sniff[i]¬Declared != 0 && optional[n] {
+ // Ignore optional undeclared identifiers.
+ // Don't report an error, and skip adding n to the needType array.
+ continue
+ }
error_(f.NamePos[n], "could not determine kind of name for C.%s", fixGo(n.Go))
case notStrLiteral | notType:
n.Kind = "iconst"
case notIntConst | notNumConst | notStrLiteral | notType:
n.Kind = "not-type"
}
+ needType = append(needType, n)
}
if nerrors > 0 {
// Check if compiling the preamble by itself causes any errors,
fatalf("unresolved names")
}
- needType = append(needType, names...)
return needType
}
// Record types and typedef information.
var conv typeConv
conv.Init(p.PtrSize, p.IntSize)
+ for i, n := range names {
+ if strings.HasSuffix(n.Go, "GetTypeID") && types[i].String() == "func() CFTypeID" {
+ conv.getTypeIDs[n.Go[:len(n.Go)-9]] = true
+ }
+ }
for i, n := range names {
if types[i] == nil {
continue
// Keys of ptrs in insertion order (deterministic worklist)
ptrKeys []dwarf.Type
+ // Type names X for which there exists an XGetTypeID function with type func() CFTypeID.
+ getTypeIDs map[string]bool
+
// Predeclared types.
bool ast.Expr
byte ast.Expr // denotes padding
c.intSize = intSize
c.m = make(map[dwarf.Type]*Type)
c.ptrs = make(map[dwarf.Type][]*Type)
+ c.getTypeIDs = make(map[string]bool)
c.bool = c.Ident("bool")
c.byte = c.Ident("byte")
c.int8 = c.Ident("int8")
name := c.Ident("_Ctype_" + dt.Name)
goIdent[name.Name] = name
sub := c.Type(dt.Type, pos)
- if badPointerTypedef(dt) {
+ if c.badPointerTypedef(dt) {
// Treat this typedef as a uintptr.
s := *sub
s.Go = c.uintptr
}
// ...or the typedef is one in which we expect bad pointers.
// It will be a uintptr instead of *X.
- if badPointerTypedef(dt) {
+ if c.badPointerTypedef(dt) {
break
}
// A typedef is bad if C code sometimes stores non-pointers in this type.
// TODO: Currently our best solution is to find these manually and list them as
// they come up. A better solution is desired.
-func badPointerTypedef(dt *dwarf.TypedefType) bool {
- if badCFType(dt) {
+func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
+ if c.badCFType(dt) {
return true
}
- if badJNI(dt) {
+ if c.badJNI(dt) {
return true
}
return false
}
-func badCFType(dt *dwarf.TypedefType) bool {
+func (c *typeConv) badCFType(dt *dwarf.TypedefType) bool {
// The real bad types are CFNumberRef and CFDateRef.
// Sometimes non-pointers are stored in these types.
// CFTypeRef is a supertype of those, so it can have bad pointers in it as well.
- // We return true for the other CF*Ref types just so casting between them is easier.
+ // We return true for the other *Ref types just so casting between them is easier.
+ // We identify the correct set of types as those ending in Ref and for which
+ // there exists a corresponding GetTypeID function.
// See comment below for details about the bad pointers.
- return goos == "darwin" && strings.HasPrefix(dt.Name, "CF") && strings.HasSuffix(dt.Name, "Ref")
+ if goos != "darwin" {
+ return false
+ }
+ s := dt.Name
+ if !strings.HasSuffix(s, "Ref") {
+ return false
+ }
+ s = s[:len(s)-3]
+ if s == "CFType" {
+ return true
+ }
+ if c.getTypeIDs[s] {
+ return true
+ }
+ if i := strings.Index(s, "Mutable"); i >= 0 && c.getTypeIDs[s[:i]+s[i+7:]] {
+ // Mutable and immutable variants share a type ID.
+ return true
+ }
+ return false
}
// Comment from Darwin's CFInternal.h
};
*/
-func badJNI(dt *dwarf.TypedefType) bool {
+func (c *typeConv) badJNI(dt *dwarf.TypedefType) bool {
// In Dalvik and ART, the jobject type in the JNI interface of the JVM has the
// property that it is sometimes (always?) a small integer instead of a real pointer.
// Note: although only the android JVMs are bad in this respect, we declare the JNI types
// Additional help topics:
//
// c calling between Go and C
-// buildmode description of build modes
+// buildmode build modes
+// cache build and test caching
// filetype file types
// gopath GOPATH environment variable
// environment environment variables
// importpath import path syntax
-// packages description of package lists
-// testflag description of testing flags
-// testfunc description of testing functions
+// packages package lists
+// testflag testing flags
+// testfunc testing functions
//
// Use "go help [topic]" for more information about that topic.
//
// 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 ./...',
-// and even 'go test .').
-//
-// In local directory mode, go test compiles and tests the package sources
-// found in the current directory and then runs the resulting test binary.
-// In this mode, caching (discussed below) is disabled. After the package test
-// finishes, go test prints a summary line showing the test status ('ok' or 'FAIL'),
-// package name, and elapsed time.
-//
-// In package list mode, go test compiles and tests each of the packages
-// listed on the command line. If a package test passes, go test prints only
-// the final 'ok' summary line. If a package test fails, go test prints the
-// full test output. If invoked with the -bench or -v flag, go test prints
-// the full output even for passing package tests, in order to display the
+// All test output and summary lines are printed to the go command's
+// standard output, even if the test printed them to its own standard
+// error. (The go command's standard error is reserved for printing
+// errors building the tests.)
+//
+// Go test runs in two different modes:
+//
+// The first, called local directory mode, occurs when go test is
+// invoked with no package arguments (for example, 'go test' or 'go
+// test -v'). In this mode, go test compiles the package sources and
+// tests found in the current directory and then runs the resulting
+// test binary. In this mode, caching (discussed below) is disabled.
+// After the package test finishes, go test prints a summary line
+// showing the test status ('ok' or 'FAIL'), package name, and elapsed
+// time.
+//
+// The second, called package list mode, occurs when go test is invoked
+// with explicit package arguments (for example 'go test math', 'go
+// test ./...', and even 'go test .'). In this mode, go test compiles
+// and tests each of the packages listed on the command line. If a
+// package test passes, go test prints only the final 'ok' summary
+// line. If a package test fails, go test prints the full test output.
+// If invoked with the -bench or -v flag, go test prints the full
+// output even for passing package tests, in order to display the
// requested benchmark results or verbose logging.
//
-// All test output and summary lines are printed to the go command's standard
-// output, even if the test printed them to its own standard error.
-// (The go command's standard error is reserved for printing errors building
-// the tests.)
-//
-// In package list mode, go test also caches successful package test results.
-// If go test has cached a previous test run using the same test binary and
-// the same command line consisting entirely of cacheable test flags
-// (defined as -cpu, -list, -parallel, -run, -short, and -v),
-// go test will redisplay the previous output instead of running the test
-// binary again. In the summary line, go test prints '(cached)' in place of
-// the elapsed time. To disable test caching, use any test flag or argument
-// other than the cacheable flags. The idiomatic way to disable test caching
-// explicitly is to use -count=1. A cached result is treated as executing in
-// no time at all, so a successful package test result will be cached and reused
+// In package list mode only, go test caches successful package test
+// results to avoid unnecessary repeated running of tests. When the
+// result of a test can be recovered from the cache, go test will
+// redisplay the previous output instead of running the test binary
+// again. When this happens, go test prints '(cached)' in place of the
+// elapsed time in the summary line.
+//
+// The rule for a match in the cache is that the run involves the same
+// test binary and the flags on the command line come entirely from a
+// restricted set of 'cacheable' test flags, defined as -cpu, -list,
+// -parallel, -run, -short, and -v. If a run of go test has any test
+// or non-test flags outside this set, the result is not cached. To
+// disable test caching, use any test flag or argument other than the
+// cacheable flags. The idiomatic way to disable test caching explicitly
+// is to use -count=1. Tests that open files within the package's source
+// root (usually $GOPATH) or that consult environment variables only
+// match future runs in which the files and environment variables are unchanged.
+// A cached test result is treated as executing in no time at all,
+// so a successful package test result will be cached and reused
// regardless of -timeout setting.
//
// In addition to the build flags, the flags handled by 'go test' itself are:
// the C or C++ compiler, respectively, to use.
//
//
-// Description of build modes
+// Build modes
//
// The 'go build' and 'go install' commands take a -buildmode argument which
// indicates which kind of object file is to be built. Currently supported values
// import, into a Go plugin. Packages not named main are ignored.
//
//
+// Build and test caching
+//
+// The go command caches build outputs for reuse in future builds.
+// The default location for cache data is a subdirectory named go-build
+// in the standard user cache directory for the current operating system.
+// Setting the GOCACHE environment variable overrides this default,
+// and running 'go env GOCACHE' prints the current cache directory.
+//
+// The go command periodically deletes cached data that has not been
+// used recently. Running 'go clean -cache' deletes all cached data.
+//
+// The build cache correctly accounts for changes to Go source files,
+// compilers, compiler options, and so on: cleaning the cache explicitly
+// should not be necessary in typical use. However, the build cache
+// does not detect changes to C libraries imported with cgo.
+// If you have made changes to the C libraries on your system, you
+// will need to clean the cache explicitly or else use the -a build flag
+// (see 'go help build') to force rebuilding of packages that
+// depend on the updated C libraries.
+//
+// The go command also caches successful package test results.
+// See 'go help test' for details. Running 'go clean -testcache' removes
+// all cached test results (but not cached build results).
+//
+// The GODEBUG environment variable can enable printing of debugging
+// information about the state of the cache:
+//
+// GODEBUG=gocacheverify=1 causes the go command to bypass the
+// use of any cache entries and instead rebuild everything and check
+// that the results match existing cache entries.
+//
+// GODEBUG=gocachehash=1 causes the go command to print the inputs
+// for all of the content hashes it uses to construct cache lookup keys.
+// The output is voluminous but can be useful for debugging the cache.
+//
+// GODEBUG=gocachetest=1 causes the go command to print details of its
+// decisions about whether to reuse a cached test result.
+//
+//
// File types
//
// The go command examines the contents of a restricted set of files
// See https://golang.org/s/go14customimport for details.
//
//
-// Description of package lists
+// Package lists
//
// Many commands apply to a set of packages:
//
// by the go tool, as are directories named "testdata".
//
//
-// Description of testing flags
+// Testing flags
//
// The 'go test' command takes both flags that apply to 'go test' itself
// and flags that apply to the resulting test binary.
// binary, instead of being interpreted as the package list.
//
//
-// Description of testing functions
+// Testing functions
//
// The 'go test' command expects to find test, benchmark, and example functions
// in the "*_test.go" files corresponding to the package under test.
checkCoverage(tg, data)
}
+func TestCoverageDotImport(t *testing.T) {
+ skipIfGccgo(t, "gccgo has no cover tool")
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ tg.run("test", "-coverpkg=coverdot1,coverdot2", "coverdot2")
+ data := tg.getStdout() + tg.getStderr()
+ checkCoverage(tg, data)
+}
+
// Check that coverage analysis uses set mode.
// Also check that coverage profiles merge correctly.
func TestCoverageUsesSetMode(t *testing.T) {
tg.run("vet", "-printf=false", "vetpkg")
}
+// Issue 23395.
+func TestGoVetWithOnlyTestFiles(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.tempFile("src/p/p_test.go", "package p; import \"testing\"; func TestMe(*testing.T) {}")
+ tg.setenv("GOPATH", tg.path("."))
+ tg.run("vet", "p")
+}
+
// Issue 9767, 19769.
func TestGoGetDotSlashDownload(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
switch runtime.GOOS {
case "windows":
dir = os.Getenv("LocalAppData")
+ if dir == "" {
+ // Fall back to %AppData%, the old name of
+ // %LocalAppData% on Windows XP.
+ dir = os.Getenv("AppData")
+ }
if dir == "" {
return "off"
}
var HelpPackages = &base.Command{
UsageLine: "packages",
- Short: "description of package lists",
+ Short: "package lists",
Long: `
Many commands apply to a set of packages:
var HelpBuildmode = &base.Command{
UsageLine: "buildmode",
- Short: "description of build modes",
+ Short: "build modes",
Long: `
The 'go build' and 'go install' commands take a -buildmode argument which
indicates which kind of object file is to be built. Currently supported values
import, into a Go plugin. Packages not named main are ignored.
`,
}
+
+var HelpCache = &base.Command{
+ UsageLine: "cache",
+ Short: "build and test caching",
+ Long: `
+The go command caches build outputs for reuse in future builds.
+The default location for cache data is a subdirectory named go-build
+in the standard user cache directory for the current operating system.
+Setting the GOCACHE environment variable overrides this default,
+and running 'go env GOCACHE' prints the current cache directory.
+
+The go command periodically deletes cached data that has not been
+used recently. Running 'go clean -cache' deletes all cached data.
+
+The build cache correctly accounts for changes to Go source files,
+compilers, compiler options, and so on: cleaning the cache explicitly
+should not be necessary in typical use. However, the build cache
+does not detect changes to C libraries imported with cgo.
+If you have made changes to the C libraries on your system, you
+will need to clean the cache explicitly or else use the -a build flag
+(see 'go help build') to force rebuilding of packages that
+depend on the updated C libraries.
+
+The go command also caches successful package test results.
+See 'go help test' for details. Running 'go clean -testcache' removes
+all cached test results (but not cached build results).
+
+The GODEBUG environment variable can enable printing of debugging
+information about the state of the cache:
+
+GODEBUG=gocacheverify=1 causes the go command to bypass the
+use of any cache entries and instead rebuild everything and check
+that the results match existing cache entries.
+
+GODEBUG=gocachehash=1 causes the go command to print the inputs
+for all of the content hashes it uses to construct cache lookup keys.
+The output is voluminous but can be useful for debugging the cache.
+
+GODEBUG=gocachetest=1 causes the go command to print details of its
+decisions about whether to reuse a cached test result.
+`,
+}
return pkg
}
+
+// GetTestPackagesFor returns package structs ptest, the package p plus
+// its test files, and pxtest, the external tests of package p.
+// pxtest may be nil. If there are no test files, forceTest decides
+// whether this returns a new package struct or just returns p.
+func GetTestPackagesFor(p *Package, forceTest bool) (ptest, pxtest *Package, err error) {
+ var imports, ximports []*Package
+ var stk ImportStack
+ stk.Push(p.ImportPath + " (test)")
+ rawTestImports := str.StringList(p.TestImports)
+ for i, path := range p.TestImports {
+ p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], UseVendor)
+ if cfg.BuildToolchainName == "gccgo" && p1.Standard {
+ continue
+ }
+ if p1.Error != nil {
+ return nil, nil, p1.Error
+ }
+ if len(p1.DepsErrors) > 0 {
+ err := p1.DepsErrors[0]
+ err.Pos = "" // show full import stack
+ return nil, nil, err
+ }
+ if str.Contains(p1.Deps, p.ImportPath) || p1.ImportPath == p.ImportPath {
+ // Same error that loadPackage returns (via reusePackage) in pkg.go.
+ // Can't change that code, because that code is only for loading the
+ // non-test copy of a package.
+ err := &PackageError{
+ ImportStack: testImportStack(stk[0], p1, p.ImportPath),
+ Err: "import cycle not allowed in test",
+ IsImportCycle: true,
+ }
+ return nil, nil, err
+ }
+ p.TestImports[i] = p1.ImportPath
+ imports = append(imports, p1)
+ }
+ stk.Pop()
+ stk.Push(p.ImportPath + "_test")
+ pxtestNeedsPtest := false
+ rawXTestImports := str.StringList(p.XTestImports)
+ for i, path := range p.XTestImports {
+ p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], UseVendor)
+ if cfg.BuildToolchainName == "gccgo" && p1.Standard {
+ continue
+ }
+ if p1.Error != nil {
+ return nil, nil, p1.Error
+ }
+ if len(p1.DepsErrors) > 0 {
+ err := p1.DepsErrors[0]
+ err.Pos = "" // show full import stack
+ return nil, nil, err
+ }
+ if p1.ImportPath == p.ImportPath {
+ pxtestNeedsPtest = true
+ } else {
+ ximports = append(ximports, p1)
+ }
+ p.XTestImports[i] = p1.ImportPath
+ }
+ stk.Pop()
+
+ // Test package.
+ if len(p.TestGoFiles) > 0 || forceTest {
+ ptest = new(Package)
+ *ptest = *p
+ ptest.GoFiles = nil
+ ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...)
+ ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...)
+ ptest.Target = ""
+ // 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
+ m := map[string][]token.Position{}
+ for k, v := range p.Internal.Build.ImportPos {
+ m[k] = append(m[k], v...)
+ }
+ for k, v := range p.Internal.Build.TestImportPos {
+ m[k] = append(m[k], v...)
+ }
+ ptest.Internal.Build.ImportPos = m
+ } else {
+ ptest = p
+ }
+
+ // External test package.
+ if len(p.XTestGoFiles) > 0 {
+ pxtest = &Package{
+ PackagePublic: PackagePublic{
+ Name: p.Name + "_test",
+ ImportPath: p.ImportPath + "_test",
+ Root: p.Root,
+ Dir: p.Dir,
+ GoFiles: p.XTestGoFiles,
+ Imports: p.XTestImports,
+ },
+ Internal: PackageInternal{
+ LocalPrefix: p.Internal.LocalPrefix,
+ Build: &build.Package{
+ ImportPos: p.Internal.Build.XTestImportPos,
+ },
+ Imports: ximports,
+ RawImports: rawXTestImports,
+
+ Asmflags: p.Internal.Asmflags,
+ Gcflags: p.Internal.Gcflags,
+ Ldflags: p.Internal.Ldflags,
+ Gccgoflags: p.Internal.Gccgoflags,
+ },
+ }
+ if pxtestNeedsPtest {
+ pxtest.Internal.Imports = append(pxtest.Internal.Imports, ptest)
+ }
+ }
+
+ return ptest, pxtest, nil
+}
+
+func testImportStack(top string, p *Package, target string) []string {
+ stk := []string{top, p.ImportPath}
+Search:
+ for p.ImportPath != target {
+ for _, p1 := range p.Internal.Imports {
+ if p1.ImportPath == target || str.Contains(p1.Deps, target) {
+ stk = append(stk, p1.ImportPath)
+ p = p1
+ continue Search
+ }
+ }
+ // Can't happen, but in case it does...
+ stk = append(stk, "<lost path to cycle>")
+ break
+ }
+ return stk
+}
import (
"bytes"
+ "crypto/sha256"
"errors"
"fmt"
"go/ast"
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 ./...',
-and even 'go test .').
-
-In local directory mode, go test compiles and tests the package sources
-found in the current directory and then runs the resulting test binary.
-In this mode, caching (discussed below) is disabled. After the package test
-finishes, go test prints a summary line showing the test status ('ok' or 'FAIL'),
-package name, and elapsed time.
-
-In package list mode, go test compiles and tests each of the packages
-listed on the command line. If a package test passes, go test prints only
-the final 'ok' summary line. If a package test fails, go test prints the
-full test output. If invoked with the -bench or -v flag, go test prints
-the full output even for passing package tests, in order to display the
+All test output and summary lines are printed to the go command's
+standard output, even if the test printed them to its own standard
+error. (The go command's standard error is reserved for printing
+errors building the tests.)
+
+Go test runs in two different modes:
+
+The first, called local directory mode, occurs when go test is
+invoked with no package arguments (for example, 'go test' or 'go
+test -v'). In this mode, go test compiles the package sources and
+tests found in the current directory and then runs the resulting
+test binary. In this mode, caching (discussed below) is disabled.
+After the package test finishes, go test prints a summary line
+showing the test status ('ok' or 'FAIL'), package name, and elapsed
+time.
+
+The second, called package list mode, occurs when go test is invoked
+with explicit package arguments (for example 'go test math', 'go
+test ./...', and even 'go test .'). In this mode, go test compiles
+and tests each of the packages listed on the command line. If a
+package test passes, go test prints only the final 'ok' summary
+line. If a package test fails, go test prints the full test output.
+If invoked with the -bench or -v flag, go test prints the full
+output even for passing package tests, in order to display the
requested benchmark results or verbose logging.
-All test output and summary lines are printed to the go command's standard
-output, even if the test printed them to its own standard error.
-(The go command's standard error is reserved for printing errors building
-the tests.)
-
-In package list mode, go test also caches successful package test results.
-If go test has cached a previous test run using the same test binary and
-the same command line consisting entirely of cacheable test flags
-(defined as -cpu, -list, -parallel, -run, -short, and -v),
-go test will redisplay the previous output instead of running the test
-binary again. In the summary line, go test prints '(cached)' in place of
-the elapsed time. To disable test caching, use any test flag or argument
-other than the cacheable flags. The idiomatic way to disable test caching
-explicitly is to use -count=1. A cached result is treated as executing in
-no time at all, so a successful package test result will be cached and reused
+In package list mode only, go test caches successful package test
+results to avoid unnecessary repeated running of tests. When the
+result of a test can be recovered from the cache, go test will
+redisplay the previous output instead of running the test binary
+again. When this happens, go test prints '(cached)' in place of the
+elapsed time in the summary line.
+
+The rule for a match in the cache is that the run involves the same
+test binary and the flags on the command line come entirely from a
+restricted set of 'cacheable' test flags, defined as -cpu, -list,
+-parallel, -run, -short, and -v. If a run of go test has any test
+or non-test flags outside this set, the result is not cached. To
+disable test caching, use any test flag or argument other than the
+cacheable flags. The idiomatic way to disable test caching explicitly
+is to use -count=1. Tests that open files within the package's source
+root (usually $GOPATH) or that consult environment variables only
+match future runs in which the files and environment variables are unchanged.
+A cached test result is treated as executing in no time at all,
+so a successful package test result will be cached and reused
regardless of -timeout setting.
` + strings.TrimSpace(testFlag1) + ` See 'go help testflag' for details.
var HelpTestflag = &base.Command{
UsageLine: "testflag",
- Short: "description of testing flags",
+ Short: "testing flags",
Long: `
The 'go test' command takes both flags that apply to 'go test' itself
and flags that apply to the resulting test binary.
var HelpTestfunc = &base.Command{
UsageLine: "testfunc",
- Short: "description of testing functions",
+ Short: "testing functions",
Long: `
The 'go test' command expects to find test, benchmark, and example functions
in the "*_test.go" files corresponding to the package under test.
// pmain - pkg.test binary
var ptest, pxtest, pmain *load.Package
- 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 cfg.BuildToolchainName == "gccgo" && p1.Standard {
- continue
- }
- if p1.Error != nil {
- return nil, nil, nil, p1.Error
- }
- if len(p1.DepsErrors) > 0 {
- err := p1.DepsErrors[0]
- err.Pos = "" // show full import stack
- return nil, nil, nil, err
- }
- if str.Contains(p1.Deps, p.ImportPath) || p1.ImportPath == p.ImportPath {
- // Same error that loadPackage returns (via reusePackage) in pkg.go.
- // Can't change that code, because that code is only for loading the
- // non-test copy of a package.
- err := &load.PackageError{
- ImportStack: testImportStack(stk[0], p1, p.ImportPath),
- Err: "import cycle not allowed in test",
- IsImportCycle: true,
- }
- return nil, nil, nil, err
- }
- p.TestImports[i] = p1.ImportPath
- imports = append(imports, p1)
- }
- 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 cfg.BuildToolchainName == "gccgo" && p1.Standard {
- continue
- }
- if p1.Error != nil {
- return nil, nil, nil, p1.Error
- }
- if len(p1.DepsErrors) > 0 {
- err := p1.DepsErrors[0]
- err.Pos = "" // show full import stack
- return nil, nil, nil, err
- }
- if p1.ImportPath == p.ImportPath {
- pxtestNeedsPtest = true
- } else {
- ximports = append(ximports, p1)
- }
- p.XTestImports[i] = p1.ImportPath
+ localCover := testCover && testCoverPaths == nil
+
+ ptest, pxtest, err = load.GetTestPackagesFor(p, localCover || p.Name == "main")
+ if err != nil {
+ return nil, nil, nil, err
}
- stk.Pop()
// Use last element of import path, not package name.
// They differ when package name is "main".
// only for this package and only for this test?
// Yes, if -cover is on but -coverpkg has not specified
// a list of packages for global coverage.
- localCover := testCover && testCoverPaths == nil
-
- // Test package.
- if len(p.TestGoFiles) > 0 || localCover || p.Name == "main" {
- ptest = new(load.Package)
- *ptest = *p
- ptest.GoFiles = nil
- ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...)
- ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...)
- ptest.Target = ""
- // 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
- m := map[string][]token.Position{}
- for k, v := range p.Internal.Build.ImportPos {
- m[k] = append(m[k], v...)
- }
- for k, v := range p.Internal.Build.TestImportPos {
- m[k] = append(m[k], v...)
- }
- ptest.Internal.Build.ImportPos = m
-
- if localCover {
- ptest.Internal.CoverMode = testCoverMode
- var coverFiles []string
- coverFiles = append(coverFiles, ptest.GoFiles...)
- coverFiles = append(coverFiles, ptest.CgoFiles...)
- ptest.Internal.CoverVars = declareCoverVars(ptest.ImportPath, coverFiles...)
- }
- } else {
- ptest = p
- }
-
- // External test package.
- if len(p.XTestGoFiles) > 0 {
- pxtest = &load.Package{
- PackagePublic: load.PackagePublic{
- Name: p.Name + "_test",
- ImportPath: p.ImportPath + "_test",
- Root: p.Root,
- Dir: p.Dir,
- GoFiles: p.XTestGoFiles,
- Imports: p.XTestImports,
- },
- Internal: load.PackageInternal{
- LocalPrefix: p.Internal.LocalPrefix,
- Build: &build.Package{
- ImportPos: p.Internal.Build.XTestImportPos,
- },
- Imports: ximports,
- RawImports: rawXTestImports,
-
- Asmflags: p.Internal.Asmflags,
- Gcflags: p.Internal.Gcflags,
- Ldflags: p.Internal.Ldflags,
- Gccgoflags: p.Internal.Gccgoflags,
- },
- }
- if pxtestNeedsPtest {
- pxtest.Internal.Imports = append(pxtest.Internal.Imports, ptest)
- }
+ if localCover {
+ ptest.Internal.CoverMode = testCoverMode
+ var coverFiles []string
+ coverFiles = append(coverFiles, ptest.GoFiles...)
+ coverFiles = append(coverFiles, ptest.CgoFiles...)
+ ptest.Internal.CoverVars = declareCoverVars(ptest.ImportPath, coverFiles...)
}
testDir := b.NewObjdir()
// The generated main also imports testing, regexp, and os.
// Also the linker introduces implicit dependencies reported by LinkerDeps.
+ var stk load.ImportStack
stk.Push("testmain")
deps := testMainDeps // cap==len, so safe for append
for _, d := range load.LinkerDeps(p) {
}
}
-func testImportStack(top string, p *load.Package, target string) []string {
- stk := []string{top, p.ImportPath}
-Search:
- for p.ImportPath != target {
- for _, p1 := range p.Internal.Imports {
- if p1.ImportPath == target || str.Contains(p1.Deps, target) {
- stk = append(stk, p1.ImportPath)
- p = p1
- continue Search
- }
- }
- // Can't happen, but in case it does...
- stk = append(stk, "<lost path to cycle>")
- break
- }
- return stk
-}
-
func recompileForTest(pmain, preal, ptest, pxtest *load.Package) {
// The "test copy" of preal is ptest.
// For each package that depends on preal, make a "test copy"
func declareCoverVars(importPath string, files ...string) map[string]*load.CoverVar {
coverVars := make(map[string]*load.CoverVar)
coverIndex := 0
+ // We create the cover counters as new top-level variables in the package.
+ // We need to avoid collisions with user variables (GoCover_0 is unlikely but still)
+ // and more importantly with dot imports of other covered packages,
+ // so we append 12 hex digits from the SHA-256 of the import path.
+ // The point is only to avoid accidents, not to defeat users determined to
+ // break things.
+ sum := sha256.Sum256([]byte(importPath))
+ h := fmt.Sprintf("%x", sum[:6])
for _, file := range files {
if isTestFile(file) {
continue
}
coverVars[file] = &load.CoverVar{
File: filepath.Join(importPath, file),
- Var: fmt.Sprintf("GoCover_%d", coverIndex),
+ Var: fmt.Sprintf("GoCover_%d_%x", coverIndex, h),
}
coverIndex++
}
root := &work.Action{Mode: "go vet"}
for _, p := range pkgs {
- root.Deps = append(root.Deps, b.VetAction(work.ModeBuild, work.ModeBuild, p))
+ ptest, pxtest, err := load.GetTestPackagesFor(p, false)
+ if err != nil {
+ base.Errorf("%v", err)
+ continue
+ }
+ if len(ptest.GoFiles) == 0 && pxtest == nil {
+ base.Errorf("go vet %s: no Go files in %s", p.ImportPath, p.Dir)
+ continue
+ }
+ if len(ptest.GoFiles) > 0 {
+ root.Deps = append(root.Deps, b.VetAction(work.ModeBuild, work.ModeBuild, ptest))
+ }
+ if pxtest != nil {
+ root.Deps = append(root.Deps, b.VetAction(work.ModeBuild, work.ModeBuild, pxtest))
+ }
}
b.Do(root)
}
// it is not present in another shared library, add it here.
// TODO(rsc): Maybe this should only happen if "runtime" is in the original package set.
// TODO(rsc): This should probably be changed to use load.LinkerDeps(p).
- // TODO(rsc): Find out and explain here why gccgo is excluded.
- // If the answer is that gccgo is different in implicit linker deps, maybe
- // load.LinkerDeps should be used and updated.
- // Link packages into a shared library.
-
+ // TODO(rsc): We don't add standard library imports for gccgo
+ // because they are all always linked in anyhow.
+ // Maybe load.LinkerDeps should be used and updated.
a := &Action{
Mode: "go build -buildmode=shared",
Package: p,
// Need to look for install header actions depending on this action,
// or depending on a link that depends on this action.
needHeader := false
- if (a.Package.UsesCgo() || a.Package.UsesSwig()) && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-header") {
+ if (a.Package.UsesCgo() || a.Package.UsesSwig()) && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared") {
for _, t1 := range a.triggers {
if t1.Mode == "install header" {
needHeader = true
func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string, allactions []*Action, buildmode, desc string) error {
// gccgo needs explicit linking with all package dependencies,
// and all LDFLAGS from cgo dependencies.
- apackagePathsSeen := make(map[string]bool)
afiles := []string{}
shlibs := []string{}
ldflags := b.gccArchArgs()
return newArchive, nil
}
- actionsSeen := make(map[*Action]bool)
- // Make a pre-order depth-first traversal of the action graph, taking note of
- // whether a shared library action has been seen on the way to an action (the
- // construction of the graph means that if any path to a node passes through
- // a shared library action, they all do).
- var walk func(a *Action, seenShlib bool)
- var err error
- walk = func(a *Action, seenShlib bool) {
- if actionsSeen[a] {
- return
- }
- actionsSeen[a] = true
- if a.Package != nil && !seenShlib {
- if a.Package.Standard {
- return
+ // If using -linkshared, find the shared library deps.
+ haveShlib := make(map[string]bool)
+ targetBase := filepath.Base(root.Target)
+ if cfg.BuildLinkshared {
+ for _, a := range root.Deps {
+ p := a.Package
+ if p == nil || p.Shlib == "" {
+ continue
}
- // We record the target of the first time we see a .a file
- // for a package to make sure that we prefer the 'install'
- // rather than the 'build' location (which may not exist any
- // more). We still need to traverse the dependencies of the
- // build action though so saying
- // if apackagePathsSeen[a.Package.ImportPath] { return }
- // doesn't work.
- if !apackagePathsSeen[a.Package.ImportPath] {
- apackagePathsSeen[a.Package.ImportPath] = true
- target := a.built
- if len(a.Package.CgoFiles) > 0 || a.Package.UsesSwig() {
- target, err = readAndRemoveCgoFlags(target)
- if err != nil {
- return
- }
- }
- afiles = append(afiles, target)
+
+ // The .a we are linking into this .so
+ // will have its Shlib set to this .so.
+ // Don't start thinking we want to link
+ // this .so into itself.
+ base := filepath.Base(p.Shlib)
+ if base != targetBase {
+ haveShlib[base] = true
}
}
- if strings.HasSuffix(a.Target, ".so") {
- shlibs = append(shlibs, a.Target)
- seenShlib = true
+ }
+
+ // Arrange the deps into afiles and shlibs.
+ addedShlib := make(map[string]bool)
+ for _, a := range root.Deps {
+ p := a.Package
+ if p != nil && p.Shlib != "" && haveShlib[filepath.Base(p.Shlib)] {
+ // This is a package linked into a shared
+ // library that we will put into shlibs.
+ continue
}
- for _, a1 := range a.Deps {
- walk(a1, seenShlib)
- if err != nil {
- return
+
+ if haveShlib[filepath.Base(a.Target)] {
+ // This is a shared library we want to link againt.
+ if !addedShlib[a.Target] {
+ shlibs = append(shlibs, a.Target)
+ addedShlib[a.Target] = true
}
+ continue
}
- }
- for _, a1 := range root.Deps {
- walk(a1, false)
- if err != nil {
- return err
+
+ if p != nil {
+ target := a.built
+ if p.UsesCgo() || p.UsesSwig() {
+ var err error
+ target, err = readAndRemoveCgoFlags(target)
+ if err != nil {
+ continue
+ }
+ }
+
+ afiles = append(afiles, target)
}
}
}
func (tools gccgoToolchain) ldShared(b *Builder, root *Action, toplevelactions []*Action, out, importcfg string, allactions []*Action) error {
- fakeRoot := *root
- fakeRoot.Deps = toplevelactions
- return tools.link(b, &fakeRoot, out, importcfg, allactions, "shared", out)
+ return tools.link(b, root, out, importcfg, allactions, "shared", out)
}
func (tools gccgoToolchain) cc(b *Builder, a *Action, ofile, cfile string) error {
help.HelpC,
help.HelpBuildmode,
+ help.HelpCache,
help.HelpFileType,
help.HelpGopath,
help.HelpEnvironment,
// If opts.Roots is nil and system roots are unavailable the returned error
// will be of type SystemRootsError.
//
-// WARNING: this doesn't do any revocation checking.
+// Name constraints in the intermediates will be applied to all names claimed
+// in the chain, not just opts.DNSName. Thus it is invalid for a leaf to claim
+// example.com if an intermediate doesn't permit it, even if example.com is not
+// the name being validated. Note that DirectoryName constraints are not
+// supported.
+//
+// Extended Key Usage values are enforced down a chain, so an intermediate or
+// root that enumerates EKUs prevents a leaf from asserting an EKU not in that
+// list.
+//
+// WARNING: this function doesn't do any revocation checking.
func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
// Platform-specific verification needs the ASN.1 contents so
// this makes the behavior consistent across platforms.
scaniface interface{}
)
-var conversionTests = []conversionTest{
- // Exact conversions (destination pointer type matches source type)
- {s: "foo", d: &scanstr, wantstr: "foo"},
- {s: 123, d: &scanint, wantint: 123},
- {s: someTime, d: &scantime, wanttime: someTime},
-
- // To strings
- {s: "string", d: &scanstr, wantstr: "string"},
- {s: []byte("byteslice"), d: &scanstr, wantstr: "byteslice"},
- {s: 123, d: &scanstr, wantstr: "123"},
- {s: int8(123), d: &scanstr, wantstr: "123"},
- {s: int64(123), d: &scanstr, wantstr: "123"},
- {s: uint8(123), d: &scanstr, wantstr: "123"},
- {s: uint16(123), d: &scanstr, wantstr: "123"},
- {s: uint32(123), d: &scanstr, wantstr: "123"},
- {s: uint64(123), d: &scanstr, wantstr: "123"},
- {s: 1.5, d: &scanstr, wantstr: "1.5"},
-
- // From time.Time:
- {s: time.Unix(1, 0).UTC(), d: &scanstr, wantstr: "1970-01-01T00:00:01Z"},
- {s: time.Unix(1453874597, 0).In(time.FixedZone("here", -3600*8)), d: &scanstr, wantstr: "2016-01-26T22:03:17-08:00"},
- {s: time.Unix(1, 2).UTC(), d: &scanstr, wantstr: "1970-01-01T00:00:01.000000002Z"},
- {s: time.Time{}, d: &scanstr, wantstr: "0001-01-01T00:00:00Z"},
- {s: time.Unix(1, 2).UTC(), d: &scanbytes, wantbytes: []byte("1970-01-01T00:00:01.000000002Z")},
- {s: time.Unix(1, 2).UTC(), d: &scaniface, wantiface: time.Unix(1, 2).UTC()},
-
- // To []byte
- {s: nil, d: &scanbytes, wantbytes: nil},
- {s: "string", d: &scanbytes, wantbytes: []byte("string")},
- {s: []byte("byteslice"), d: &scanbytes, wantbytes: []byte("byteslice")},
- {s: 123, d: &scanbytes, wantbytes: []byte("123")},
- {s: int8(123), d: &scanbytes, wantbytes: []byte("123")},
- {s: int64(123), d: &scanbytes, wantbytes: []byte("123")},
- {s: uint8(123), d: &scanbytes, wantbytes: []byte("123")},
- {s: uint16(123), d: &scanbytes, wantbytes: []byte("123")},
- {s: uint32(123), d: &scanbytes, wantbytes: []byte("123")},
- {s: uint64(123), d: &scanbytes, wantbytes: []byte("123")},
- {s: 1.5, d: &scanbytes, wantbytes: []byte("1.5")},
-
- // To RawBytes
- {s: nil, d: &scanraw, wantraw: nil},
- {s: []byte("byteslice"), d: &scanraw, wantraw: RawBytes("byteslice")},
- {s: "string", d: &scanraw, wantraw: RawBytes("string")},
- {s: 123, d: &scanraw, wantraw: RawBytes("123")},
- {s: int8(123), d: &scanraw, wantraw: RawBytes("123")},
- {s: int64(123), d: &scanraw, wantraw: RawBytes("123")},
- {s: uint8(123), d: &scanraw, wantraw: RawBytes("123")},
- {s: uint16(123), d: &scanraw, wantraw: RawBytes("123")},
- {s: uint32(123), d: &scanraw, wantraw: RawBytes("123")},
- {s: uint64(123), d: &scanraw, wantraw: RawBytes("123")},
- {s: 1.5, d: &scanraw, wantraw: RawBytes("1.5")},
- // time.Time has been placed here to check that the RawBytes slice gets
- // correctly reset when calling time.Time.AppendFormat.
- {s: time.Unix(2, 5).UTC(), d: &scanraw, wantraw: RawBytes("1970-01-01T00:00:02.000000005Z")},
-
- // Strings to integers
- {s: "255", d: &scanuint8, wantuint: 255},
- {s: "256", d: &scanuint8, wanterr: "converting driver.Value type string (\"256\") to a uint8: value out of range"},
- {s: "256", d: &scanuint16, wantuint: 256},
- {s: "-1", d: &scanint, wantint: -1},
- {s: "foo", d: &scanint, wanterr: "converting driver.Value type string (\"foo\") to a int: invalid syntax"},
-
- // int64 to smaller integers
- {s: int64(5), d: &scanuint8, wantuint: 5},
- {s: int64(256), d: &scanuint8, wanterr: "converting driver.Value type int64 (\"256\") to a uint8: value out of range"},
- {s: int64(256), d: &scanuint16, wantuint: 256},
- {s: int64(65536), d: &scanuint16, wanterr: "converting driver.Value type int64 (\"65536\") to a uint16: value out of range"},
-
- // True bools
- {s: true, d: &scanbool, wantbool: true},
- {s: "True", d: &scanbool, wantbool: true},
- {s: "TRUE", d: &scanbool, wantbool: true},
- {s: "1", d: &scanbool, wantbool: true},
- {s: 1, d: &scanbool, wantbool: true},
- {s: int64(1), d: &scanbool, wantbool: true},
- {s: uint16(1), d: &scanbool, wantbool: true},
-
- // False bools
- {s: false, d: &scanbool, wantbool: false},
- {s: "false", d: &scanbool, wantbool: false},
- {s: "FALSE", d: &scanbool, wantbool: false},
- {s: "0", d: &scanbool, wantbool: false},
- {s: 0, d: &scanbool, wantbool: false},
- {s: int64(0), d: &scanbool, wantbool: false},
- {s: uint16(0), d: &scanbool, wantbool: false},
-
- // Not bools
- {s: "yup", d: &scanbool, wanterr: `sql/driver: couldn't convert "yup" into type bool`},
- {s: 2, d: &scanbool, wanterr: `sql/driver: couldn't convert 2 into type bool`},
-
- // Floats
- {s: float64(1.5), d: &scanf64, wantf64: float64(1.5)},
- {s: int64(1), d: &scanf64, wantf64: float64(1)},
- {s: float64(1.5), d: &scanf32, wantf32: float32(1.5)},
- {s: "1.5", d: &scanf32, wantf32: float32(1.5)},
- {s: "1.5", d: &scanf64, wantf64: float64(1.5)},
-
- // Pointers
- {s: interface{}(nil), d: &scanptr, wantnil: true},
- {s: int64(42), d: &scanptr, wantptr: &answer},
-
- // To interface{}
- {s: float64(1.5), d: &scaniface, wantiface: float64(1.5)},
- {s: int64(1), d: &scaniface, wantiface: int64(1)},
- {s: "str", d: &scaniface, wantiface: "str"},
- {s: []byte("byteslice"), d: &scaniface, wantiface: []byte("byteslice")},
- {s: true, d: &scaniface, wantiface: true},
- {s: nil, d: &scaniface},
- {s: []byte(nil), d: &scaniface, wantiface: []byte(nil)},
-
- // To a user-defined type
- {s: 1.5, d: new(userDefined), wantusrdef: 1.5},
- {s: int64(123), d: new(userDefined), wantusrdef: 123},
- {s: "1.5", d: new(userDefined), wantusrdef: 1.5},
- {s: []byte{1, 2, 3}, d: new(userDefinedSlice), wanterr: `unsupported Scan, storing driver.Value type []uint8 into type *sql.userDefinedSlice`},
- {s: "str", d: new(userDefinedString), wantusrstr: "str"},
-
- // Other errors
- {s: complex(1, 2), d: &scanstr, wanterr: `unsupported Scan, storing driver.Value type complex128 into type *string`},
+func conversionTests() []conversionTest {
+ // Return a fresh instance to test so "go test -count 2" works correctly.
+ return []conversionTest{
+ // Exact conversions (destination pointer type matches source type)
+ {s: "foo", d: &scanstr, wantstr: "foo"},
+ {s: 123, d: &scanint, wantint: 123},
+ {s: someTime, d: &scantime, wanttime: someTime},
+
+ // To strings
+ {s: "string", d: &scanstr, wantstr: "string"},
+ {s: []byte("byteslice"), d: &scanstr, wantstr: "byteslice"},
+ {s: 123, d: &scanstr, wantstr: "123"},
+ {s: int8(123), d: &scanstr, wantstr: "123"},
+ {s: int64(123), d: &scanstr, wantstr: "123"},
+ {s: uint8(123), d: &scanstr, wantstr: "123"},
+ {s: uint16(123), d: &scanstr, wantstr: "123"},
+ {s: uint32(123), d: &scanstr, wantstr: "123"},
+ {s: uint64(123), d: &scanstr, wantstr: "123"},
+ {s: 1.5, d: &scanstr, wantstr: "1.5"},
+
+ // From time.Time:
+ {s: time.Unix(1, 0).UTC(), d: &scanstr, wantstr: "1970-01-01T00:00:01Z"},
+ {s: time.Unix(1453874597, 0).In(time.FixedZone("here", -3600*8)), d: &scanstr, wantstr: "2016-01-26T22:03:17-08:00"},
+ {s: time.Unix(1, 2).UTC(), d: &scanstr, wantstr: "1970-01-01T00:00:01.000000002Z"},
+ {s: time.Time{}, d: &scanstr, wantstr: "0001-01-01T00:00:00Z"},
+ {s: time.Unix(1, 2).UTC(), d: &scanbytes, wantbytes: []byte("1970-01-01T00:00:01.000000002Z")},
+ {s: time.Unix(1, 2).UTC(), d: &scaniface, wantiface: time.Unix(1, 2).UTC()},
+
+ // To []byte
+ {s: nil, d: &scanbytes, wantbytes: nil},
+ {s: "string", d: &scanbytes, wantbytes: []byte("string")},
+ {s: []byte("byteslice"), d: &scanbytes, wantbytes: []byte("byteslice")},
+ {s: 123, d: &scanbytes, wantbytes: []byte("123")},
+ {s: int8(123), d: &scanbytes, wantbytes: []byte("123")},
+ {s: int64(123), d: &scanbytes, wantbytes: []byte("123")},
+ {s: uint8(123), d: &scanbytes, wantbytes: []byte("123")},
+ {s: uint16(123), d: &scanbytes, wantbytes: []byte("123")},
+ {s: uint32(123), d: &scanbytes, wantbytes: []byte("123")},
+ {s: uint64(123), d: &scanbytes, wantbytes: []byte("123")},
+ {s: 1.5, d: &scanbytes, wantbytes: []byte("1.5")},
+
+ // To RawBytes
+ {s: nil, d: &scanraw, wantraw: nil},
+ {s: []byte("byteslice"), d: &scanraw, wantraw: RawBytes("byteslice")},
+ {s: "string", d: &scanraw, wantraw: RawBytes("string")},
+ {s: 123, d: &scanraw, wantraw: RawBytes("123")},
+ {s: int8(123), d: &scanraw, wantraw: RawBytes("123")},
+ {s: int64(123), d: &scanraw, wantraw: RawBytes("123")},
+ {s: uint8(123), d: &scanraw, wantraw: RawBytes("123")},
+ {s: uint16(123), d: &scanraw, wantraw: RawBytes("123")},
+ {s: uint32(123), d: &scanraw, wantraw: RawBytes("123")},
+ {s: uint64(123), d: &scanraw, wantraw: RawBytes("123")},
+ {s: 1.5, d: &scanraw, wantraw: RawBytes("1.5")},
+ // time.Time has been placed here to check that the RawBytes slice gets
+ // correctly reset when calling time.Time.AppendFormat.
+ {s: time.Unix(2, 5).UTC(), d: &scanraw, wantraw: RawBytes("1970-01-01T00:00:02.000000005Z")},
+
+ // Strings to integers
+ {s: "255", d: &scanuint8, wantuint: 255},
+ {s: "256", d: &scanuint8, wanterr: "converting driver.Value type string (\"256\") to a uint8: value out of range"},
+ {s: "256", d: &scanuint16, wantuint: 256},
+ {s: "-1", d: &scanint, wantint: -1},
+ {s: "foo", d: &scanint, wanterr: "converting driver.Value type string (\"foo\") to a int: invalid syntax"},
+
+ // int64 to smaller integers
+ {s: int64(5), d: &scanuint8, wantuint: 5},
+ {s: int64(256), d: &scanuint8, wanterr: "converting driver.Value type int64 (\"256\") to a uint8: value out of range"},
+ {s: int64(256), d: &scanuint16, wantuint: 256},
+ {s: int64(65536), d: &scanuint16, wanterr: "converting driver.Value type int64 (\"65536\") to a uint16: value out of range"},
+
+ // True bools
+ {s: true, d: &scanbool, wantbool: true},
+ {s: "True", d: &scanbool, wantbool: true},
+ {s: "TRUE", d: &scanbool, wantbool: true},
+ {s: "1", d: &scanbool, wantbool: true},
+ {s: 1, d: &scanbool, wantbool: true},
+ {s: int64(1), d: &scanbool, wantbool: true},
+ {s: uint16(1), d: &scanbool, wantbool: true},
+
+ // False bools
+ {s: false, d: &scanbool, wantbool: false},
+ {s: "false", d: &scanbool, wantbool: false},
+ {s: "FALSE", d: &scanbool, wantbool: false},
+ {s: "0", d: &scanbool, wantbool: false},
+ {s: 0, d: &scanbool, wantbool: false},
+ {s: int64(0), d: &scanbool, wantbool: false},
+ {s: uint16(0), d: &scanbool, wantbool: false},
+
+ // Not bools
+ {s: "yup", d: &scanbool, wanterr: `sql/driver: couldn't convert "yup" into type bool`},
+ {s: 2, d: &scanbool, wanterr: `sql/driver: couldn't convert 2 into type bool`},
+
+ // Floats
+ {s: float64(1.5), d: &scanf64, wantf64: float64(1.5)},
+ {s: int64(1), d: &scanf64, wantf64: float64(1)},
+ {s: float64(1.5), d: &scanf32, wantf32: float32(1.5)},
+ {s: "1.5", d: &scanf32, wantf32: float32(1.5)},
+ {s: "1.5", d: &scanf64, wantf64: float64(1.5)},
+
+ // Pointers
+ {s: interface{}(nil), d: &scanptr, wantnil: true},
+ {s: int64(42), d: &scanptr, wantptr: &answer},
+
+ // To interface{}
+ {s: float64(1.5), d: &scaniface, wantiface: float64(1.5)},
+ {s: int64(1), d: &scaniface, wantiface: int64(1)},
+ {s: "str", d: &scaniface, wantiface: "str"},
+ {s: []byte("byteslice"), d: &scaniface, wantiface: []byte("byteslice")},
+ {s: true, d: &scaniface, wantiface: true},
+ {s: nil, d: &scaniface},
+ {s: []byte(nil), d: &scaniface, wantiface: []byte(nil)},
+
+ // To a user-defined type
+ {s: 1.5, d: new(userDefined), wantusrdef: 1.5},
+ {s: int64(123), d: new(userDefined), wantusrdef: 123},
+ {s: "1.5", d: new(userDefined), wantusrdef: 1.5},
+ {s: []byte{1, 2, 3}, d: new(userDefinedSlice), wanterr: `unsupported Scan, storing driver.Value type []uint8 into type *sql.userDefinedSlice`},
+ {s: "str", d: new(userDefinedString), wantusrstr: "str"},
+
+ // Other errors
+ {s: complex(1, 2), d: &scanstr, wanterr: `unsupported Scan, storing driver.Value type complex128 into type *string`},
+ }
}
func intPtrValue(intptr interface{}) interface{} {
}
func TestConversions(t *testing.T) {
- for n, ct := range conversionTests {
+ for n, ct := range conversionTests() {
err := convertAssign(ct.d, ct.s)
errstr := ""
if err != nil {
var v_used bool
if ident != nil {
if _, obj := check.scope.LookupParent(ident.Name, token.NoPos); obj != nil {
- v, _ = obj.(*Var)
- if v != nil {
+ // It's ok to mark non-local variables, but ignore variables
+ // from other packages to avoid potential race conditions with
+ // dot-imported variables.
+ if w, _ := obj.(*Var); w != nil && w.pkg == check.pkg {
+ v = w
v_used = v.used
}
}
l := len(lhs)
get, r, commaOk := unpack(func(x *operand, i int) { check.multiExpr(x, rhs[i]) }, len(rhs), l == 2)
if get == nil {
+ check.useLHS(lhs...)
return // error reported by unpack
}
if l != r {
// use type-checks each argument.
// Useful to make sure expressions are evaluated
// (and variables are "used") in the presence of other errors.
+// The arguments may be nil.
func (check *Checker) use(arg ...ast.Expr) {
var x operand
for _, e := range arg {
- if e != nil { // be safe
+ // The nil check below is necessary since certain AST fields
+ // may legally be nil (e.g., the ast.SliceExpr.High field).
+ if e != nil {
check.rawExpr(&x, e, nil)
}
}
}
+// useLHS is like use, but doesn't "use" top-level identifiers.
+// It should be called instead of use if the arguments are
+// expressions on the lhs of an assignment.
+// The arguments must not be nil.
+func (check *Checker) useLHS(arg ...ast.Expr) {
+ var x operand
+ for _, e := range arg {
+ // If the lhs is an identifier denoting a variable v, this assignment
+ // is not a 'use' of v. Remember current value of v.used and restore
+ // after evaluating the lhs via check.rawExpr.
+ var v *Var
+ var v_used bool
+ if ident, _ := unparen(e).(*ast.Ident); ident != nil {
+ // never type-check the blank name on the lhs
+ if ident.Name == "_" {
+ continue
+ }
+ if _, obj := check.scope.LookupParent(ident.Name, token.NoPos); obj != nil {
+ // It's ok to mark non-local variables, but ignore variables
+ // from other packages to avoid potential race conditions with
+ // dot-imported variables.
+ if w, _ := obj.(*Var); w != nil && w.pkg == check.pkg {
+ v = w
+ v_used = v.used
+ }
+ }
+ }
+ check.rawExpr(&x, e, nil)
+ if v != nil {
+ v.used = v_used // restore v.used
+ }
+ }
+}
+
// useGetter is like use, but takes a getter instead of a list of expressions.
// It should be called instead of use if a getter is present to avoid repeated
// evaluation of the first argument (since the getter was likely obtained via
if typ != nil {
t := check.typ(typ)
if !isConstType(t) {
- check.errorf(typ.Pos(), "invalid constant type %s", t)
+ // don't report an error if the type is an invalid C (defined) type
+ // (issue #22090)
+ if t.Underlying() != Typ[Invalid] {
+ check.errorf(typ.Pos(), "invalid constant type %s", t)
+ }
obj.typ = Typ[Invalid]
return
}
// declaration, but the post statement must not."
if s, _ := s.Post.(*ast.AssignStmt); s != nil && s.Tok == token.DEFINE {
check.softErrorf(s.Pos(), "cannot declare in post statement")
+ // Don't call useLHS here because we want to use the lhs in
+ // this erroneous statement so that we don't get errors about
+ // these lhs variables being declared but not used.
check.use(s.Lhs...) // avoid follow-up errors
}
check.stmt(inner, s.Body)
import _ /* ERROR cannot rename import "C" */ "C"
import foo /* ERROR cannot rename import "C" */ "C"
import . /* ERROR cannot rename import "C" */ "C"
+
+// Test cases extracted from issue #22090.
+
+import "unsafe"
+
+const _ C.int = 0xff // no error due to invalid constant type
+
+type T struct {
+ Name string
+ Ordinal int
+}
+
+func f(args []T) {
+ var s string
+ for i, v := range args {
+ cname := C.CString(v.Name)
+ args[i].Ordinal = int(C.sqlite3_bind_parameter_index(s, cname)) // no error due to i not being "used"
+ C.free(unsafe.Pointer(cname))
+ }
+}
+
+type CType C.Type
+
+const _ CType = C.X // no error due to invalid constant type
+const _ = C.X
}
case *Var:
+ // It's ok to mark non-local variables, but ignore variables
+ // from other packages to avoid potential race conditions with
+ // dot-imported variables.
if obj.pkg == check.pkg {
obj.used = true
}
// Method needs three ins: receiver, *args, *reply.
if mtype.NumIn() != 3 {
if reportErr {
- log.Println("method", mname, "has wrong number of ins:", mtype.NumIn())
+ log.Printf("rpc.Register: method %q has %d input parameters; needs exactly three\n", mname, mtype.NumIn())
}
continue
}
argType := mtype.In(1)
if !isExportedOrBuiltinType(argType) {
if reportErr {
- log.Println(mname, "argument type not exported:", argType)
+ log.Printf("rpc.Register: argument type of method %q is not exported: %q\n", mname, argType)
}
continue
}
replyType := mtype.In(2)
if replyType.Kind() != reflect.Ptr {
if reportErr {
- log.Println("method", mname, "reply type not a pointer:", replyType)
+ log.Printf("rpc.Register: reply type of method %q is not a pointer: %q\n", mname, replyType)
}
continue
}
// Reply type must be exported.
if !isExportedOrBuiltinType(replyType) {
if reportErr {
- log.Println("method", mname, "reply type not exported:", replyType)
+ log.Printf("rpc.Register: reply type of method %q is not exported: %q\n", mname, replyType)
}
continue
}
// Method needs one out.
if mtype.NumOut() != 1 {
if reportErr {
- log.Println("method", mname, "has wrong number of outs:", mtype.NumOut())
+ log.Printf("rpc.Register: method %q has %d output parameters; needs exactly one\n", mname, mtype.NumOut())
}
continue
}
// The return type of the method must be error.
if returnType := mtype.Out(0); returnType != typeOfError {
if reportErr {
- log.Println("method", mname, "returns", returnType.String(), "not error")
+ log.Printf("rpc.Register: return type of method %q is %q, must be error\n", mname, returnType)
}
continue
}
package os
func isExist(err error) bool {
- return checkErrMessageContent(err, " exists")
+ return checkErrMessageContent(err, "exists", "is a directory")
}
func isNotExist(err error) bool {
// reached via multiple paths (due to symbolic links),
// Getwd may return any one of them.
func Getwd() (dir string, err error) {
- if runtime.GOOS == "windows" {
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
return syscall.Getwd()
}
}
t.Errorf("test ran %d times without producing expected output", tries)
}
+
+func TestBadTraceback(t *testing.T) {
+ if runtime.Compiler == "gccgo" {
+ t.Skip("gccgo does not do a hex dump")
+ }
+ output := runTestProg(t, "testprog", "BadTraceback")
+ for _, want := range []string{
+ "runtime: unexpected return pc",
+ "called from 0xbad",
+ "00000bad", // Smashed LR in hex dump
+ "<main.badLR", // Symbolization in hex dump (badLR1 or badLR2)
+ } {
+ if !strings.Contains(output, want) {
+ t.Errorf("output does not contain %q:\n%s", want, output)
+ }
+ }
+}
return *e._type.string
}
-// For calling from C.
-// Prints an argument passed to panic.
+// printany prints an argument passed to panic.
func printany(i interface{}) {
switch v := i.(type) {
case nil:
}
// Print all currently active panics. Used when crashing.
+// Should only be called after preprintpanics.
func printpanics(p *_panic) {
if p.link != nil {
printpanics(p.link)
print("\t")
}
print("panic: ")
+ // Because of preprintpanics, p.arg cannot be an error or
+ // stringer, so this won't call into user code.
printany(p.arg)
if p.recovered {
print(" [recovered]")
// so that two concurrent panics don't overlap their output.
var paniclk mutex
-// startpanic_m implements unrecoverable panic.
+// startpanic_m prepares for an unrecoverable panic.
//
// It can have write barriers because the write barrier explicitly
// ignores writes once dying > 0.
//go:yeswritebarrierrec
func startpanic() {
_g_ := getg()
- // Uncomment when mheap_ is in Go.
- // if mheap_.cachealloc.size == 0 { // very early
- // print("runtime: panic before malloc heap initialized\n")
- // _g_.m.mallocing = 1 // tell rest of panic not to try to malloc
- // } else
- if _g_.m.mcache == nil { // can happen if called from signal handler or throw
- _g_.m.mcache = allocmcache()
+ if mheap_.cachealloc.size == 0 { // very early
+ print("runtime: panic before malloc heap initialized\n")
}
+ // Disallow malloc during an unrecoverable panic. A panic
+ // could happen in a signal handler, or in a throw, or inside
+ // malloc itself. We want to catch if an allocation ever does
+ // happen (even if we're not in one of these situations).
+ _g_.m.mallocing++
switch _g_.m.dying {
case 0:
exit(2)
}
+// canpanic returns false if a signal should throw instead of
+// panicking.
+//
//go:nosplit
func canpanic(gp *g) bool {
// Note that g is m->gsignal, different from gp.
// as the pprof-proto format output. Translations from cycle count to time duration
// are done because The proto expects count and time (nanoseconds) instead of count
// and the number of cycles for block, contention profiles.
-func printCountCycleProfile(w io.Writer, countName, cycleName string, records []runtime.BlockProfileRecord) error {
+// Possible 'scaler' functions are scaleBlockProfile and scaleMutexProfile.
+func printCountCycleProfile(w io.Writer, countName, cycleName string, scaler func(int64, float64) (int64, float64), records []runtime.BlockProfileRecord) error {
// Output profile in protobuf form.
b := newProfileBuilder(w)
b.pbValueType(tagProfile_PeriodType, countName, "count")
values := []int64{0, 0}
var locs []uint64
for _, r := range records {
- values[0] = int64(r.Count)
- values[1] = int64(float64(r.Cycles) / cpuGHz) // to nanoseconds
+ count, nanosec := scaler(r.Count, float64(r.Cycles)/cpuGHz)
+ values[0] = count
+ values[1] = int64(nanosec)
locs = locs[:0]
for _, addr := range r.Stack() {
// For count profiles, all stack addresses are
sort.Slice(p, func(i, j int) bool { return p[i].Cycles > p[j].Cycles })
if debug <= 0 {
- return printCountCycleProfile(w, "contentions", "delay", p)
+ return printCountCycleProfile(w, "contentions", "delay", scaleBlockProfile, p)
}
b := bufio.NewWriter(w)
return b.Flush()
}
+func scaleBlockProfile(cnt int64, ns float64) (int64, float64) {
+ // Do nothing.
+ // The current way of block profile sampling makes it
+ // hard to compute the unsampled number. The legacy block
+ // profile parse doesn't attempt to scale or unsample.
+ return cnt, ns
+}
+
// writeMutex writes the current mutex profile to w.
func writeMutex(w io.Writer, debug int) error {
// TODO(pjw): too much common code with writeBlock. FIX!
sort.Slice(p, func(i, j int) bool { return p[i].Cycles > p[j].Cycles })
if debug <= 0 {
- return printCountCycleProfile(w, "contentions", "delay", p)
+ return printCountCycleProfile(w, "contentions", "delay", scaleMutexProfile, p)
}
b := bufio.NewWriter(w)
return b.Flush()
}
+func scaleMutexProfile(cnt int64, ns float64) (int64, float64) {
+ period := runtime.SetMutexProfileFraction(-1)
+ return cnt * int64(period), ns * float64(period)
+}
+
func runtime_cyclesPerSecond() int64
// This is a copy of sync/rwmutex.go rewritten to work in the runtime.
-// An rwmutex is a reader/writer mutual exclusion lock.
+// A rwmutex is a reader/writer mutual exclusion lock.
// The lock can be held by an arbitrary number of readers or a single writer.
// This is a variant of sync.RWMutex, for the runtime package.
// Like mutex, rwmutex blocks the calling M.
if sig < uint32(len(sigtable)) {
flags = sigtable[sig].flags
}
+ if flags&_SigPanic != 0 && gp.throwsplit {
+ // We can't safely sigpanic because it may grow the
+ // stack. Abort in the signal handler instead.
+ flags = (flags &^ _SigPanic) | _SigThrow
+ }
if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
// Emulate gc by passing arguments out of band,
// although we don't really have to.
// the signal handler. The effect is that the program will act as
// though the function that got the signal simply called sigpanic
// instead.
+//
+// This must NOT be nosplit because the linker doesn't know where
+// sigpanic calls can be injected.
+//
+// The signal handler must not inject a call to sigpanic if
+// getg().throwsplit, since sigpanic may need to grow the stack.
func sigpanic() {
g := getg()
if !canpanic(g) {
return t.tb
}
+//go:notinheap
type timersBucket struct {
lock mutex
gp *g
// There is a modified copy of this file in runtime/rwmutex.go.
// If you make any changes here, see if you should make them there.
-// An RWMutex is a reader/writer mutual exclusion lock.
+// A RWMutex is a reader/writer mutual exclusion lock.
// The lock can be held by an arbitrary number of readers or a single writer.
// The zero value for a RWMutex is an unlocked mutex.
//
-// An RWMutex must not be copied after first use.
+// A RWMutex must not be copied after first use.
//
// If a goroutine holds a RWMutex for reading and another goroutine might
// call Lock, no goroutine should expect to be able to acquire a read lock
// not locked for writing on entry to Unlock.
//
// As with Mutexes, a locked RWMutex is not associated with a particular
-// goroutine. One goroutine may RLock (Lock) an RWMutex and then
+// goroutine. One goroutine may RLock (Lock) a RWMutex and then
// arrange for another goroutine to RUnlock (Unlock) it.
func (rw *RWMutex) Unlock() {
if race.Enabled {
body: `var wg sync.WaitGroup; wg.Add(100); for i := 0; i < 100; i++ { go func(i int) { for j := 0; j < 100; j++ { C.f(); runtime.GOMAXPROCS(i) }; wg.Done() }(i) }; wg.Wait()`,
fail: false,
},
+ {
+ // Test poller deadline with cgocheck=2. Issue #23435.
+ name: "deadline",
+ c: `#define US 10`,
+ imports: []string{"os", "time"},
+ body: `r, _, _ := os.Pipe(); r.SetDeadline(time.Now().Add(C.US * time.Microsecond))`,
+ fail: false,
+ },
}
func TestPointerChecks(t *testing.T) {
t.Logf("%s", out)
expectSignal(t, err, syscall.SIGPIPE)
}
+
+// Test that installing a second time recreates the header files.
+func TestCachedInstall(t *testing.T) {
+ defer os.RemoveAll("pkg")
+
+ h1 := filepath.Join("pkg", libgodir, "libgo.h")
+ h2 := filepath.Join("pkg", libgodir, "p.h")
+
+ buildcmd := []string{"go", "install", "-i", "-buildmode=c-archive", "libgo"}
+
+ cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
+ cmd.Env = gopathEnv
+ t.Log(buildcmd)
+ if out, err := cmd.CombinedOutput(); err != nil {
+ t.Logf("%s", out)
+ t.Fatal(err)
+ }
+
+ if _, err := os.Stat(h1); err != nil {
+ t.Errorf("libgo.h not installed: %v", err)
+ }
+ if _, err := os.Stat(h2); err != nil {
+ t.Errorf("p.h not installed: %v", err)
+ }
+
+ if err := os.Remove(h1); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.Remove(h2); err != nil {
+ t.Fatal(err)
+ }
+
+ cmd = exec.Command(buildcmd[0], buildcmd[1:]...)
+ cmd.Env = gopathEnv
+ t.Log(buildcmd)
+ if out, err := cmd.CombinedOutput(); err != nil {
+ t.Logf("%s", out)
+ t.Fatal(err)
+ }
+
+ if _, err := os.Stat(h1); err != nil {
+ t.Errorf("libgo.h not installed in second run: %v", err)
+ }
+ if _, err := os.Stat(h2); err != nil {
+ t.Errorf("p.h not installed in second run: %v", err)
+ }
+}
import (
"debug/elf"
"fmt"
+ "io/ioutil"
"log"
"os"
"os/exec"
androiddir = fmt.Sprintf("/data/local/tmp/testcshared-%d", os.Getpid())
if GOOS == "android" {
- cmd := exec.Command("adb", "shell", "mkdir", "-p", androiddir)
+ args := append(adbCmd(), "shell", "mkdir", "-p", androiddir)
+ cmd := exec.Command(args[0], args[1:]...)
out, err := cmd.CombinedOutput()
if err != nil {
log.Fatalf("setupAndroid failed: %v\n%s\n", err, out)
return "./" + name + exeSuffix
}
+func adbCmd() []string {
+ cmd := []string{"adb"}
+ if flags := os.Getenv("GOANDROID_ADB_FLAGS"); flags != "" {
+ cmd = append(cmd, strings.Split(flags, " ")...)
+ }
+ return cmd
+}
+
func adbPush(t *testing.T, filename string) {
if GOOS != "android" {
return
}
- args := []string{"adb", "push", filename, fmt.Sprintf("%s/%s", androiddir, filename)}
+ args := append(adbCmd(), "push", filename, fmt.Sprintf("%s/%s", androiddir, filename))
cmd := exec.Command(args[0], args[1:]...)
if out, err := cmd.CombinedOutput(); err != nil {
t.Fatalf("adb command failed: %v\n%s\n", err, out)
if GOOS != "android" {
t.Fatalf("trying to run adb command when operating system is not android.")
}
- args := []string{"adb", "shell"}
+ args := append(adbCmd(), "shell")
// Propagate LD_LIBRARY_PATH to the adb shell invocation.
for _, e := range env {
if strings.Index(e, "LD_LIBRARY_PATH=") != -1 {
}
if GOOS == "android" {
- args = []string{"adb", "push", libgoname, fmt.Sprintf("%s/%s", androiddir, libgoname)}
+ args = append(adbCmd(), "push", libgoname, fmt.Sprintf("%s/%s", androiddir, libgoname))
cmd = exec.Command(args[0], args[1:]...)
out, err = cmd.CombinedOutput()
if err != nil {
if GOOS != "android" {
return
}
- cmd := exec.Command("adb", "shell", "rm", "-rf", androiddir)
+ args := append(adbCmd(), "shell", "rm", "-rf", androiddir)
+ cmd := exec.Command(args[0], args[1:]...)
out, err := cmd.CombinedOutput()
if err != nil {
log.Fatalf("cleanupAndroid failed: %v\n%s\n", err, out)
}
}
}
+
+// Test that installing a second time recreates the header files.
+func TestCachedInstall(t *testing.T) {
+ tmpdir, err := ioutil.TempDir("", "cshared")
+ if err != nil {
+ t.Fatal(err)
+ }
+ // defer os.RemoveAll(tmpdir)
+
+ copyFile(t, filepath.Join(tmpdir, "src", "libgo", "libgo.go"), filepath.Join("src", "libgo", "libgo.go"))
+ copyFile(t, filepath.Join(tmpdir, "src", "p", "p.go"), filepath.Join("src", "p", "p.go"))
+
+ env := append(os.Environ(), "GOPATH="+tmpdir)
+
+ buildcmd := []string{"go", "install", "-x", "-i", "-buildmode=c-shared", "-installsuffix", "testcshared", "libgo"}
+
+ cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
+ cmd.Env = env
+ t.Log(buildcmd)
+ out, err := cmd.CombinedOutput()
+ t.Logf("%s", out)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var libgoh, ph string
+
+ walker := func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ t.Fatal(err)
+ }
+ var ps *string
+ switch filepath.Base(path) {
+ case "libgo.h":
+ ps = &libgoh
+ case "p.h":
+ ps = &ph
+ }
+ if ps != nil {
+ if *ps != "" {
+ t.Fatalf("%s found again", *ps)
+ }
+ *ps = path
+ }
+ return nil
+ }
+
+ if err := filepath.Walk(tmpdir, walker); err != nil {
+ t.Fatal(err)
+ }
+
+ if libgoh == "" {
+ t.Fatal("libgo.h not installed")
+ }
+ if ph == "" {
+ t.Fatal("p.h not installed")
+ }
+
+ if err := os.Remove(libgoh); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.Remove(ph); err != nil {
+ t.Fatal(err)
+ }
+
+ cmd = exec.Command(buildcmd[0], buildcmd[1:]...)
+ cmd.Env = env
+ t.Log(buildcmd)
+ out, err = cmd.CombinedOutput()
+ t.Logf("%s", out)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if _, err := os.Stat(libgoh); err != nil {
+ t.Errorf("libgo.h not installed in second run: %v", err)
+ }
+ if _, err := os.Stat(ph); err != nil {
+ t.Errorf("p.h not installed in second run: %v", err)
+ }
+}
+
+// copyFile copies src to dst.
+func copyFile(t *testing.T, dst, src string) {
+ t.Helper()
+ data, err := ioutil.ReadFile(src)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := os.MkdirAll(filepath.Dir(dst), 0777); err != nil {
+ t.Fatal(err)
+ }
+ if err := ioutil.WriteFile(dst, data, 0666); err != nil {
+ t.Fatal(err)
+ }
+}
func dynStrings(t *testing.T, path string, flag elf.DynTag) []string {
f, err := elf.Open(path)
- defer f.Close()
if err != nil {
t.Fatalf("elf.Open(%q) failed: %v", path, err)
}
+ defer f.Close()
dynstrings, err := f.DynString(flag)
if err != nil {
t.Fatalf("DynString(%s) failed on %s: %v", flag, path, err)
// If gccgo is not available or not new enough call t.Skip. Otherwise,
// return a build.Context that is set up for gccgo.
func prepGccgo(t *testing.T) build.Context {
- t.Skip("golang.org/issue/22472")
gccgoName := os.Getenv("GCCGO")
if gccgoName == "" {
gccgoName = "gccgo"
// library with gccgo, another GOPATH package that depends on the first and an
// executable that links the second library.
func TestTwoGopathShlibsGccgo(t *testing.T) {
- t.Skip("golang.org/issue/22224")
-
gccgoContext := prepGccgo(t)
libgoRE := regexp.MustCompile("libgo.so.[0-9]+")