libgo: update to Go1.10rc1

Reviewed-on: https://go-review.googlesource.com/90295

From-SVN: r257126
This commit is contained in:
Ian Lance Taylor 2018-01-27 23:44:29 +00:00
parent ace36c8bcc
commit d779dffc4b
40 changed files with 943 additions and 495 deletions

View File

@ -1,4 +1,4 @@
13b25c25faa8afd625732d2630a4f9ece5cacb2e
4164071703c531b5234b790b76df4931c37a8d9c
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.

View File

@ -1,4 +1,4 @@
594668a5a96267a46282ce3007a584ec07adf705
5348aed83e39bd1d450d92d7f627e994c2db6ebf
The first line of this file holds the git revision number of the
last merge done from the master library sources.

View File

@ -1 +1 @@
go1.10beta2
go1.10rc1

View File

@ -341,69 +341,11 @@ in unexpected and unpredictable ways.
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:
type in Go are instead represented by a uintptr. Those include:
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
1. The *Ref types on Darwin, rooted at CoreFoundation's CFTypeRef type.
Also the object types from Java's JNI interface:
2. The object types from Java's JNI interface:
jobject
jclass

View File

@ -243,6 +243,7 @@ func (p *Package) guessKinds(f *File) []*Name {
// 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
@ -279,6 +280,14 @@ func (p *Package) guessKinds(f *File) []*Name {
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)
}
@ -425,6 +434,11 @@ func (p *Package) guessKinds(f *File) []*Name {
for i, n := range names {
switch sniff[i] {
default:
if sniff[i]&notDeclared != 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"
@ -437,6 +451,7 @@ func (p *Package) guessKinds(f *File) []*Name {
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,
@ -450,7 +465,6 @@ func (p *Package) guessKinds(f *File) []*Name {
fatalf("unresolved names")
}
needType = append(needType, names...)
return needType
}
@ -565,6 +579,11 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
// 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
@ -1737,6 +1756,9 @@ type typeConv struct {
// 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
@ -1766,6 +1788,7 @@ func (c *typeConv) Init(ptrSize, intSize int64) {
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")
@ -2152,7 +2175,7 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
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
@ -2318,7 +2341,7 @@ func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
}
// ...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
}
@ -2666,23 +2689,43 @@ func fieldPrefix(fld []*ast.Field) string {
// 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
@ -2720,7 +2763,7 @@ enum {
};
*/
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

View File

@ -35,14 +35,15 @@
// 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.
//
@ -756,39 +757,51 @@
// 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 .').
// 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 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.
// Go test runs in two different modes:
//
// 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
// 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 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.
//
// 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
// 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:
@ -893,7 +906,7 @@
// 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
@ -939,6 +952,45 @@
// 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
@ -1396,7 +1448,7 @@
// See https://golang.org/s/go14customimport for details.
//
//
// Description of package lists
// Package lists
//
// Many commands apply to a set of packages:
//
@ -1478,7 +1530,7 @@
// 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.
@ -1705,7 +1757,7 @@
// 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.

View File

@ -2461,6 +2461,17 @@ func TestCoverageRuns(t *testing.T) {
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) {
@ -3243,6 +3254,16 @@ func TestGoVetWithFlagsOff(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)

View File

@ -68,6 +68,11 @@ func DefaultDir() string {
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"
}

View File

@ -30,7 +30,7 @@ the C or C++ compiler, respectively, to use.
var HelpPackages = &base.Command{
UsageLine: "packages",
Short: "description of package lists",
Short: "package lists",
Long: `
Many commands apply to a set of packages:
@ -586,7 +586,7 @@ command.
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
@ -632,3 +632,45 @@ are:
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.
`,
}

View File

@ -1526,3 +1526,153 @@ func GoFilesPackage(gofiles []string) *Package {
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
}

View File

@ -6,6 +6,7 @@ package test
import (
"bytes"
"crypto/sha256"
"errors"
"fmt"
"go/ast"
@ -79,39 +80,51 @@ 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 ./...',
and even 'go test .').
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 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.
Go test runs in two different modes:
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
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 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.
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
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.
@ -167,7 +180,7 @@ func Usage() {
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.
@ -401,7 +414,7 @@ binary, instead of being interpreted as the package list.
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.
@ -771,62 +784,12 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
// 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)
localCover := testCover && testCoverPaths == nil
ptest, pxtest, err = load.GetTestPackagesFor(p, localCover || p.Name == "main")
if err != nil {
return nil, nil, nil, err
}
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
}
stk.Pop()
// Use last element of import path, not package name.
// They differ when package name is "main".
@ -844,81 +807,12 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
// 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()
@ -948,6 +842,7 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
// 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) {
@ -1153,24 +1048,6 @@ func addTestVet(b *work.Builder, p *load.Package, runAction, installAction *work
}
}
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"
@ -1221,13 +1098,21 @@ func isTestFile(file string) bool {
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++
}

View File

@ -57,7 +57,21 @@ func runVet(cmd *base.Command, args []string) {
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)
}

View File

@ -652,11 +652,9 @@ func (b *Builder) linkSharedAction(mode, depMode BuildMode, shlib string, a1 *Ac
// 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,

View File

@ -308,7 +308,7 @@ func (b *Builder) build(a *Action) (err error) {
// 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

View File

@ -206,7 +206,6 @@ func (gccgoToolchain) pack(b *Builder, a *Action, afile string, ofiles []string)
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()
@ -294,56 +293,57 @@ func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string
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)
}
}
if strings.HasSuffix(a.Target, ".so") {
shlibs = append(shlibs, a.Target)
seenShlib = true
}
for _, a1 := range a.Deps {
walk(a1, seenShlib)
if err != nil {
return
// 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
}
}
}
for _, a1 := range root.Deps {
walk(a1, false)
if err != nil {
return err
// 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
}
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
}
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)
}
}
@ -511,9 +511,7 @@ func (tools gccgoToolchain) ld(b *Builder, root *Action, out, importcfg, mainpkg
}
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 {

View File

@ -56,6 +56,7 @@ func init() {
help.HelpC,
help.HelpBuildmode,
help.HelpCache,
help.HelpFileType,
help.HelpGopath,
help.HelpEnvironment,

View File

@ -781,7 +781,17 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
// 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.

View File

@ -64,125 +64,128 @@ var (
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},
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"},
// 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()},
// 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 []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")},
// 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"},
// 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"},
// 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},
// 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},
// 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`},
// 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)},
// 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},
// 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 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"},
// 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`},
// Other errors
{s: complex(1, 2), d: &scanstr, wanterr: `unsupported Scan, storing driver.Value type complex128 into type *string`},
}
}
func intPtrValue(intptr interface{}) interface{} {
@ -210,7 +213,7 @@ func timeValue(ptr interface{}) time.Time {
}
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 {

View File

@ -154,8 +154,11 @@ func (check *Checker) assignVar(lhs ast.Expr, x *operand) Type {
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
}
}
@ -249,6 +252,7 @@ func (check *Checker) assignVars(lhs, rhs []ast.Expr) {
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 {

View File

@ -90,15 +90,52 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
// 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

View File

@ -111,7 +111,11 @@ func (check *Checker) constDecl(obj *Const, typ, init ast.Expr) {
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
}

View File

@ -731,6 +731,9 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
// 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)

View File

@ -8,3 +8,28 @@ import "C"
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

View File

@ -86,6 +86,9 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, path []*TypeNa
}
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
}

View File

@ -296,7 +296,7 @@ func suitableMethods(typ reflect.Type, reportErr bool) map[string]*methodType {
// 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
}
@ -304,7 +304,7 @@ func suitableMethods(typ reflect.Type, reportErr bool) map[string]*methodType {
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
}
@ -312,28 +312,28 @@ func suitableMethods(typ reflect.Type, reportErr bool) map[string]*methodType {
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
}

View File

@ -5,7 +5,7 @@
package os
func isExist(err error) bool {
return checkErrMessageContent(err, " exists")
return checkErrMessageContent(err, "exists", "is a directory")
}
func isNotExist(err error) bool {

View File

@ -24,7 +24,7 @@ var useSyscallwd = func(error) bool { return true }
// 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()
}

View File

@ -632,3 +632,20 @@ retry:
}
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)
}
}
}

View File

@ -138,8 +138,7 @@ func typestring(x interface{}) string {
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:

View File

@ -403,12 +403,15 @@ func preprintpanics(p *_panic) {
}
// 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]")
@ -833,7 +836,7 @@ var panicking uint32
// 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.
@ -841,14 +844,14 @@ var paniclk mutex
//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:
@ -934,6 +937,9 @@ func dopanic(unused int) {
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.

View File

@ -350,7 +350,8 @@ type countProfile interface {
// 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")
@ -363,8 +364,9 @@ func printCountCycleProfile(w io.Writer, countName, cycleName string, records []
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
@ -820,7 +822,7 @@ func writeBlock(w io.Writer, debug int) error {
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)
@ -847,6 +849,14 @@ func writeBlock(w io.Writer, debug int) error {
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!
@ -864,7 +874,7 @@ func writeMutex(w io.Writer, debug int) error {
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)
@ -892,4 +902,9 @@ func writeMutex(w io.Writer, debug int) error {
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

View File

@ -10,7 +10,7 @@ import (
// 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.

View File

@ -40,6 +40,11 @@ func sighandler(sig uint32, info *_siginfo_t, ctxt unsafe.Pointer, gp *g) {
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.

View File

@ -320,6 +320,12 @@ func sigtrampgo(sig uint32, info *_siginfo_t, ctx unsafe.Pointer) {
// 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) {

View File

@ -59,6 +59,7 @@ func (t *timer) assignBucket() *timersBucket {
return t.tb
}
//go:notinheap
type timersBucket struct {
lock mutex
gp *g

View File

@ -13,11 +13,11 @@ import (
// 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
@ -108,7 +108,7 @@ func (rw *RWMutex) 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 {

View File

@ -349,6 +349,14 @@ var ptrTests = []ptrTest{
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) {

View File

@ -695,3 +695,50 @@ func TestCompileWithoutShared(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)
}
}

View File

@ -7,6 +7,7 @@ package cshared_test
import (
"debug/elf"
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
@ -55,7 +56,8 @@ func TestMain(m *testing.M) {
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)
@ -154,11 +156,19 @@ func cmdToRun(name string) string {
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)
@ -169,7 +179,7 @@ func adbRun(t *testing.T, env []string, adbargs ...string) string {
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 {
@ -237,7 +247,7 @@ func createHeaders() error {
}
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 {
@ -270,7 +280,8 @@ func cleanupAndroid() {
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)
@ -477,3 +488,99 @@ func TestPIE(t *testing.T) {
}
}
}
// 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)
}
}

View File

@ -351,10 +351,10 @@ func readNotes(f *elf.File) ([]*note, error) {
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)
@ -598,7 +598,6 @@ func TestThreeGopathShlibs(t *testing.T) {
// 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"
@ -648,8 +647,6 @@ func TestGoPathShlibGccgo(t *testing.T) {
// 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]+")