diff options
40 files changed, 963 insertions, 515 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 2a6e183..d8350f3 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -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. diff --git a/libgo/MERGE b/libgo/MERGE index b42c3a7..4a3c64e 100644 --- a/libgo/MERGE +++ b/libgo/MERGE @@ -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. diff --git a/libgo/VERSION b/libgo/VERSION index 9c5f795..5859fbe 100644 --- a/libgo/VERSION +++ b/libgo/VERSION @@ -1 +1 @@ -go1.10beta2 +go1.10rc1 diff --git a/libgo/go/cmd/cgo/doc.go b/libgo/go/cmd/cgo/doc.go index 0b64b31..8e4cd88 100644 --- a/libgo/go/cmd/cgo/doc.go +++ b/libgo/go/cmd/cgo/doc.go @@ -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: - - 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 diff --git a/libgo/go/cmd/cgo/gcc.go b/libgo/go/cmd/cgo/gcc.go index d9db573..fcf334e 100644 --- a/libgo/go/cmd/cgo/gcc.go +++ b/libgo/go/cmd/cgo/gcc.go @@ -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]¬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" @@ -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 } @@ -566,6 +580,11 @@ func (p *Package) loadDWARF(f *File, names []*Name) { 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 diff --git a/libgo/go/cmd/go/alldocs.go b/libgo/go/cmd/go/alldocs.go index c151fa6..85b9d25 100644 --- a/libgo/go/cmd/go/alldocs.go +++ b/libgo/go/cmd/go/alldocs.go @@ -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 .'). -// -// 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: @@ -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. diff --git a/libgo/go/cmd/go/go_test.go b/libgo/go/cmd/go/go_test.go index 7276a2c..41a37a5 100644 --- a/libgo/go/cmd/go/go_test.go +++ b/libgo/go/cmd/go/go_test.go @@ -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) diff --git a/libgo/go/cmd/go/internal/cache/default.go b/libgo/go/cmd/go/internal/cache/default.go index 8a5c12c..8285f78 100644 --- a/libgo/go/cmd/go/internal/cache/default.go +++ b/libgo/go/cmd/go/internal/cache/default.go @@ -69,6 +69,11 @@ func DefaultDir() string { 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" } diff --git a/libgo/go/cmd/go/internal/help/helpdoc.go b/libgo/go/cmd/go/internal/help/helpdoc.go index 6dcba37..126e866 100644 --- a/libgo/go/cmd/go/internal/help/helpdoc.go +++ b/libgo/go/cmd/go/internal/help/helpdoc.go @@ -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. +`, +} diff --git a/libgo/go/cmd/go/internal/load/pkg.go b/libgo/go/cmd/go/internal/load/pkg.go index 20e905c..609a47d 100644 --- a/libgo/go/cmd/go/internal/load/pkg.go +++ b/libgo/go/cmd/go/internal/load/pkg.go @@ -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 +} diff --git a/libgo/go/cmd/go/internal/test/test.go b/libgo/go/cmd/go/internal/test/test.go index b82fdd5..e77e834 100644 --- a/libgo/go/cmd/go/internal/test/test.go +++ b/libgo/go/cmd/go/internal/test/test.go @@ -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 .'). - -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. @@ -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) - } - 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". @@ -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++ } diff --git a/libgo/go/cmd/go/internal/vet/vet.go b/libgo/go/cmd/go/internal/vet/vet.go index 8b4f926..07eed89 100644 --- a/libgo/go/cmd/go/internal/vet/vet.go +++ b/libgo/go/cmd/go/internal/vet/vet.go @@ -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) } diff --git a/libgo/go/cmd/go/internal/work/action.go b/libgo/go/cmd/go/internal/work/action.go index e7a0c77..803a6bd 100644 --- a/libgo/go/cmd/go/internal/work/action.go +++ b/libgo/go/cmd/go/internal/work/action.go @@ -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, diff --git a/libgo/go/cmd/go/internal/work/exec.go b/libgo/go/cmd/go/internal/work/exec.go index edd2694..b587498 100644 --- a/libgo/go/cmd/go/internal/work/exec.go +++ b/libgo/go/cmd/go/internal/work/exec.go @@ -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 diff --git a/libgo/go/cmd/go/internal/work/gccgo.go b/libgo/go/cmd/go/internal/work/gccgo.go index dcb38af..8f55846 100644 --- a/libgo/go/cmd/go/internal/work/gccgo.go +++ b/libgo/go/cmd/go/internal/work/gccgo.go @@ -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) + + // 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) } } @@ -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 { diff --git a/libgo/go/cmd/go/main.go b/libgo/go/cmd/go/main.go index 09147ee..7558e08 100644 --- a/libgo/go/cmd/go/main.go +++ b/libgo/go/cmd/go/main.go @@ -56,6 +56,7 @@ func init() { help.HelpC, help.HelpBuildmode, + help.HelpCache, help.HelpFileType, help.HelpGopath, help.HelpEnvironment, diff --git a/libgo/go/crypto/x509/verify.go b/libgo/go/crypto/x509/verify.go index 7a6bd45..9477e85 100644 --- a/libgo/go/crypto/x509/verify.go +++ b/libgo/go/crypto/x509/verify.go @@ -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. diff --git a/libgo/go/database/sql/convert_test.go b/libgo/go/database/sql/convert_test.go index 47098c8..b0aff7b 100644 --- a/libgo/go/database/sql/convert_test.go +++ b/libgo/go/database/sql/convert_test.go @@ -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}, - - // 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{} { @@ -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 { diff --git a/libgo/go/go/types/assignments.go b/libgo/go/go/types/assignments.go index e5ea071..98c9e12 100644 --- a/libgo/go/go/types/assignments.go +++ b/libgo/go/go/types/assignments.go @@ -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 { diff --git a/libgo/go/go/types/call.go b/libgo/go/go/types/call.go index 345df66..8fe65e4 100644 --- a/libgo/go/go/types/call.go +++ b/libgo/go/go/types/call.go @@ -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 diff --git a/libgo/go/go/types/decl.go b/libgo/go/go/types/decl.go index 7428f8f..9b250b3 100644 --- a/libgo/go/go/types/decl.go +++ b/libgo/go/go/types/decl.go @@ -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 } diff --git a/libgo/go/go/types/stmt.go b/libgo/go/go/types/stmt.go index 1292f5c..5221bcc 100644 --- a/libgo/go/go/types/stmt.go +++ b/libgo/go/go/types/stmt.go @@ -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) diff --git a/libgo/go/go/types/testdata/importC.src b/libgo/go/go/types/testdata/importC.src index 31436be..f50f7f3 100644 --- a/libgo/go/go/types/testdata/importC.src +++ b/libgo/go/go/types/testdata/importC.src @@ -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 diff --git a/libgo/go/go/types/typexpr.go b/libgo/go/go/types/typexpr.go index 0ab6dfd..92ab06b 100644 --- a/libgo/go/go/types/typexpr.go +++ b/libgo/go/go/types/typexpr.go @@ -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 } diff --git a/libgo/go/net/rpc/server.go b/libgo/go/net/rpc/server.go index a021292..96e6973 100644 --- a/libgo/go/net/rpc/server.go +++ b/libgo/go/net/rpc/server.go @@ -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 } diff --git a/libgo/go/os/error_plan9.go b/libgo/go/os/error_plan9.go index a673439..b82bf0d 100644 --- a/libgo/go/os/error_plan9.go +++ b/libgo/go/os/error_plan9.go @@ -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 { diff --git a/libgo/go/os/getwd.go b/libgo/go/os/getwd.go index 87ad8eb..6d25466 100644 --- a/libgo/go/os/getwd.go +++ b/libgo/go/os/getwd.go @@ -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() } diff --git a/libgo/go/runtime/crash_test.go b/libgo/go/runtime/crash_test.go index 06200c7..7a099be 100644 --- a/libgo/go/runtime/crash_test.go +++ b/libgo/go/runtime/crash_test.go @@ -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) + } + } +} diff --git a/libgo/go/runtime/error.go b/libgo/go/runtime/error.go index 44e63d8..34b7d37 100644 --- a/libgo/go/runtime/error.go +++ b/libgo/go/runtime/error.go @@ -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: diff --git a/libgo/go/runtime/panic.go b/libgo/go/runtime/panic.go index 24d78eca..fbdb17e 100644 --- a/libgo/go/runtime/panic.go +++ b/libgo/go/runtime/panic.go @@ -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. diff --git a/libgo/go/runtime/pprof/pprof.go b/libgo/go/runtime/pprof/pprof.go index 8a562e2..be4e869 100644 --- a/libgo/go/runtime/pprof/pprof.go +++ b/libgo/go/runtime/pprof/pprof.go @@ -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 diff --git a/libgo/go/runtime/rwmutex.go b/libgo/go/runtime/rwmutex.go index 7eeb559..a6da4c9 100644 --- a/libgo/go/runtime/rwmutex.go +++ b/libgo/go/runtime/rwmutex.go @@ -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. diff --git a/libgo/go/runtime/signal_sighandler.go b/libgo/go/runtime/signal_sighandler.go index c042162..698629d 100644 --- a/libgo/go/runtime/signal_sighandler.go +++ b/libgo/go/runtime/signal_sighandler.go @@ -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. diff --git a/libgo/go/runtime/signal_unix.go b/libgo/go/runtime/signal_unix.go index 8517148..02d5348 100644 --- a/libgo/go/runtime/signal_unix.go +++ b/libgo/go/runtime/signal_unix.go @@ -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) { diff --git a/libgo/go/runtime/time.go b/libgo/go/runtime/time.go index 93181fd..b707590 100644 --- a/libgo/go/runtime/time.go +++ b/libgo/go/runtime/time.go @@ -59,6 +59,7 @@ func (t *timer) assignBucket() *timersBucket { return t.tb } +//go:notinheap type timersBucket struct { lock mutex gp *g diff --git a/libgo/go/sync/rwmutex.go b/libgo/go/sync/rwmutex.go index cb2dfe1..4e9e819 100644 --- a/libgo/go/sync/rwmutex.go +++ b/libgo/go/sync/rwmutex.go @@ -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 { diff --git a/libgo/misc/cgo/errors/ptr_test.go b/libgo/misc/cgo/errors/ptr_test.go index d295a58..fe8dfff 100644 --- a/libgo/misc/cgo/errors/ptr_test.go +++ b/libgo/misc/cgo/errors/ptr_test.go @@ -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) { diff --git a/libgo/misc/cgo/testcarchive/carchive_test.go b/libgo/misc/cgo/testcarchive/carchive_test.go index e3f6795..4a8cc0f 100644 --- a/libgo/misc/cgo/testcarchive/carchive_test.go +++ b/libgo/misc/cgo/testcarchive/carchive_test.go @@ -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) + } +} diff --git a/libgo/misc/cgo/testcshared/cshared_test.go b/libgo/misc/cgo/testcshared/cshared_test.go index 49be092..e43422d 100644 --- a/libgo/misc/cgo/testcshared/cshared_test.go +++ b/libgo/misc/cgo/testcshared/cshared_test.go @@ -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) + } +} diff --git a/libgo/misc/cgo/testshared/shared_test.go b/libgo/misc/cgo/testshared/shared_test.go index f1e8f06..cf049ec 100644 --- a/libgo/misc/cgo/testshared/shared_test.go +++ b/libgo/misc/cgo/testshared/shared_test.go @@ -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]+") |