summaryrefslogtreecommitdiff
path: root/libgo/go/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/cmd')
-rw-r--r--libgo/go/cmd/cgo/ast.go21
-rw-r--r--libgo/go/cmd/cgo/doc.go11
-rw-r--r--libgo/go/cmd/cgo/gcc.go926
-rw-r--r--libgo/go/cmd/cgo/godefs.go6
-rw-r--r--libgo/go/cmd/cgo/main.go18
-rw-r--r--libgo/go/cmd/cgo/out.go46
-rw-r--r--libgo/go/cmd/go/alldocs.go60
-rw-r--r--libgo/go/cmd/go/go_test.go163
-rw-r--r--libgo/go/cmd/go/help_test.go28
-rw-r--r--libgo/go/cmd/go/internal/cache/cache.go8
-rw-r--r--libgo/go/cmd/go/internal/cache/default.go103
-rw-r--r--libgo/go/cmd/go/internal/cache/default_unix_test.go67
-rw-r--r--libgo/go/cmd/go/internal/cache/hash.go2
-rw-r--r--libgo/go/cmd/go/internal/clean/clean.go50
-rw-r--r--libgo/go/cmd/go/internal/cmdflag/flag.go6
-rw-r--r--libgo/go/cmd/go/internal/doc/doc.go9
-rw-r--r--libgo/go/cmd/go/internal/envcmd/env.go8
-rw-r--r--libgo/go/cmd/go/internal/fix/fix.go2
-rw-r--r--libgo/go/cmd/go/internal/generate/generate.go2
-rw-r--r--libgo/go/cmd/go/internal/get/get.go23
-rw-r--r--libgo/go/cmd/go/internal/get/path.go192
-rw-r--r--libgo/go/cmd/go/internal/get/vcs.go39
-rw-r--r--libgo/go/cmd/go/internal/help/help.go20
-rw-r--r--libgo/go/cmd/go/internal/help/helpdoc.go10
-rw-r--r--libgo/go/cmd/go/internal/imports/build.go2
-rw-r--r--libgo/go/cmd/go/internal/imports/scan.go10
-rw-r--r--libgo/go/cmd/go/internal/load/pkg.go45
-rw-r--r--libgo/go/cmd/go/internal/load/test.go6
-rw-r--r--libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock.go98
-rw-r--r--libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go159
-rw-r--r--libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock_other.go36
-rw-r--r--libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock_plan9.go38
-rw-r--r--libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock_test.go209
-rw-r--r--libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock_unix.go44
-rw-r--r--libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock_windows.go66
-rw-r--r--libgo/go/cmd/go/internal/lockedfile/lockedfile.go122
-rw-r--r--libgo/go/cmd/go/internal/lockedfile/lockedfile_filelock.go64
-rw-r--r--libgo/go/cmd/go/internal/lockedfile/lockedfile_plan9.go93
-rw-r--r--libgo/go/cmd/go/internal/lockedfile/lockedfile_test.go174
-rw-r--r--libgo/go/cmd/go/internal/lockedfile/mutex.go60
-rw-r--r--libgo/go/cmd/go/internal/modcmd/download.go12
-rw-r--r--libgo/go/cmd/go/internal/modcmd/edit.go45
-rw-r--r--libgo/go/cmd/go/internal/modcmd/init.go4
-rw-r--r--libgo/go/cmd/go/internal/modcmd/tidy.go12
-rw-r--r--libgo/go/cmd/go/internal/modcmd/vendor.go18
-rw-r--r--libgo/go/cmd/go/internal/modconv/convert_test.go2
-rw-r--r--libgo/go/cmd/go/internal/modfetch/cache.go90
-rw-r--r--libgo/go/cmd/go/internal/modfetch/codehost/codehost.go50
-rw-r--r--libgo/go/cmd/go/internal/modfetch/codehost/git.go107
-rw-r--r--libgo/go/cmd/go/internal/modfetch/codehost/vcs.go105
-rw-r--r--libgo/go/cmd/go/internal/modfetch/coderepo.go72
-rw-r--r--libgo/go/cmd/go/internal/modfetch/coderepo_test.go32
-rw-r--r--libgo/go/cmd/go/internal/modfetch/fetch.go318
-rw-r--r--libgo/go/cmd/go/internal/modfetch/proxy.go32
-rw-r--r--libgo/go/cmd/go/internal/modfetch/repo.go19
-rw-r--r--libgo/go/cmd/go/internal/modfetch/unzip.go54
-rw-r--r--libgo/go/cmd/go/internal/modfile/rule.go20
-rw-r--r--libgo/go/cmd/go/internal/modget/get.go10
-rw-r--r--libgo/go/cmd/go/internal/modload/build.go102
-rw-r--r--libgo/go/cmd/go/internal/modload/help.go17
-rw-r--r--libgo/go/cmd/go/internal/modload/import.go59
-rw-r--r--libgo/go/cmd/go/internal/modload/import_test.go2
-rw-r--r--libgo/go/cmd/go/internal/modload/init.go271
-rw-r--r--libgo/go/cmd/go/internal/modload/init_test.go42
-rw-r--r--libgo/go/cmd/go/internal/modload/list.go18
-rw-r--r--libgo/go/cmd/go/internal/modload/load.go54
-rw-r--r--libgo/go/cmd/go/internal/modload/query.go20
-rw-r--r--libgo/go/cmd/go/internal/modload/query_test.go2
-rw-r--r--libgo/go/cmd/go/internal/modload/search.go5
-rw-r--r--libgo/go/cmd/go/internal/modload/testgo.go11
-rw-r--r--libgo/go/cmd/go/internal/module/module.go4
-rw-r--r--libgo/go/cmd/go/internal/module/module_test.go1
-rw-r--r--libgo/go/cmd/go/internal/mvs/mvs.go1
-rw-r--r--libgo/go/cmd/go/internal/renameio/renameio.go63
-rw-r--r--libgo/go/cmd/go/internal/run/run.go3
-rw-r--r--libgo/go/cmd/go/internal/search/search.go4
-rw-r--r--libgo/go/cmd/go/internal/semver/semver.go2
-rw-r--r--libgo/go/cmd/go/internal/semver/semver_test.go1
-rw-r--r--libgo/go/cmd/go/internal/test/test.go61
-rw-r--r--libgo/go/cmd/go/internal/test/testflag.go4
-rw-r--r--libgo/go/cmd/go/internal/vet/vet.go13
-rw-r--r--libgo/go/cmd/go/internal/vet/vetflag.go163
-rw-r--r--libgo/go/cmd/go/internal/web2/web.go8
-rw-r--r--libgo/go/cmd/go/internal/work/action.go2
-rw-r--r--libgo/go/cmd/go/internal/work/build.go6
-rw-r--r--libgo/go/cmd/go/internal/work/build_test.go14
-rw-r--r--libgo/go/cmd/go/internal/work/buildid.go59
-rw-r--r--libgo/go/cmd/go/internal/work/exec.go172
-rw-r--r--libgo/go/cmd/go/internal/work/gc.go102
-rw-r--r--libgo/go/cmd/go/internal/work/gccgo.go43
-rw-r--r--libgo/go/cmd/go/internal/work/init.go11
-rw-r--r--libgo/go/cmd/go/internal/work/security.go3
-rw-r--r--libgo/go/cmd/go/main.go32
-rw-r--r--libgo/go/cmd/go/proxy_test.go12
-rw-r--r--libgo/go/cmd/go/script_test.go288
-rw-r--r--libgo/go/cmd/go/testdata/addmod.go2
-rw-r--r--libgo/go/cmd/go/testdata/mod/research.swtch.com_vgo-tour_v1.0.0.txt23
-rw-r--r--libgo/go/cmd/go/testdata/script/README36
-rw-r--r--libgo/go/cmd/go/testdata/script/build_GOTMPDIR.txt5
-rw-r--r--libgo/go/cmd/go/testdata/script/help.txt18
-rw-r--r--libgo/go/cmd/go/testdata/script/list_bad_import.txt2
-rw-r--r--libgo/go/cmd/go/testdata/script/list_std.txt2
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_download.txt21
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_edit.txt55
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_enabled.txt6
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_fs_patterns.txt4
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_go_version.txt16
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_internal.txt13
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_list_bad_import.txt2
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_list_dir.txt4
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_nomod.txt2
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_patterns.txt10
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_readonly.txt2
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_replace.txt29
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_test.txt7
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_tidy.txt9
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_vendor.txt48
-rw-r--r--libgo/go/cmd/go/testdata/testterminal18153/terminal_test.go2
-rw-r--r--libgo/go/cmd/go/vendor_test.go2
-rw-r--r--libgo/go/cmd/gofmt/gofmt.go5
-rw-r--r--libgo/go/cmd/gofmt/gofmt_test.go2
-rw-r--r--libgo/go/cmd/gofmt/long_test.go6
-rw-r--r--libgo/go/cmd/internal/buildid/buildid.go2
-rw-r--r--libgo/go/cmd/internal/objabi/doc.go8
-rw-r--r--libgo/go/cmd/internal/objabi/flag.go13
-rw-r--r--libgo/go/cmd/internal/objabi/funcdata.go1
-rw-r--r--libgo/go/cmd/internal/objabi/funcid.go68
-rw-r--r--libgo/go/cmd/internal/objabi/head.go5
-rw-r--r--libgo/go/cmd/internal/objabi/reloctype.go2
-rw-r--r--libgo/go/cmd/internal/objabi/stack.go17
-rw-r--r--libgo/go/cmd/internal/objabi/symkind.go7
-rw-r--r--libgo/go/cmd/internal/objabi/symkind_string.go4
-rw-r--r--libgo/go/cmd/internal/objabi/util.go6
-rw-r--r--libgo/go/cmd/internal/sys/arch.go187
-rw-r--r--libgo/go/cmd/internal/sys/supported.go29
-rw-r--r--libgo/go/cmd/vet/all/main.go94
-rw-r--r--libgo/go/cmd/vet/asmdecl.go734
-rw-r--r--libgo/go/cmd/vet/assign.go52
-rw-r--r--libgo/go/cmd/vet/atomic.go71
-rw-r--r--libgo/go/cmd/vet/bool.go197
-rw-r--r--libgo/go/cmd/vet/buildtag.go126
-rw-r--r--libgo/go/cmd/vet/cgo.go141
-rw-r--r--libgo/go/cmd/vet/composite.go86
-rw-r--r--libgo/go/cmd/vet/copylock.go266
-rw-r--r--libgo/go/cmd/vet/dead.go108
-rw-r--r--libgo/go/cmd/vet/deadcode.go298
-rw-r--r--libgo/go/cmd/vet/doc.go244
-rw-r--r--libgo/go/cmd/vet/httpresponse.go137
-rw-r--r--libgo/go/cmd/vet/internal/cfg/builder.go512
-rw-r--r--libgo/go/cmd/vet/internal/cfg/cfg.go142
-rw-r--r--libgo/go/cmd/vet/internal/cfg/cfg_test.go190
-rw-r--r--libgo/go/cmd/vet/internal/whitelist/whitelist.go28
-rw-r--r--libgo/go/cmd/vet/lostcancel.go322
-rw-r--r--libgo/go/cmd/vet/main.go789
-rw-r--r--libgo/go/cmd/vet/method.go179
-rw-r--r--libgo/go/cmd/vet/nilfunc.go67
-rw-r--r--libgo/go/cmd/vet/print.go1070
-rw-r--r--libgo/go/cmd/vet/rangeloop.go105
-rw-r--r--libgo/go/cmd/vet/shadow.go246
-rw-r--r--libgo/go/cmd/vet/shift.go98
-rw-r--r--libgo/go/cmd/vet/structtag.go226
-rw-r--r--libgo/go/cmd/vet/testdata/asm/asm.go48
-rw-r--r--libgo/go/cmd/vet/testdata/asm/asm1.s315
-rw-r--r--libgo/go/cmd/vet/testdata/asm/asm2.s257
-rw-r--r--libgo/go/cmd/vet/testdata/asm/asm3.s192
-rw-r--r--libgo/go/cmd/vet/testdata/asm/asm4.s26
-rw-r--r--libgo/go/cmd/vet/testdata/asm/asm5.s193
-rw-r--r--libgo/go/cmd/vet/testdata/asm/asm6.s193
-rw-r--r--libgo/go/cmd/vet/testdata/asm/asm7.s193
-rw-r--r--libgo/go/cmd/vet/testdata/asm8.s165
-rw-r--r--libgo/go/cmd/vet/testdata/atomic.go62
-rw-r--r--libgo/go/cmd/vet/testdata/bool.go131
-rw-r--r--libgo/go/cmd/vet/testdata/buildtag/buildtag_bad.go15
-rw-r--r--libgo/go/cmd/vet/testdata/cgo/cgo.go59
-rw-r--r--libgo/go/cmd/vet/testdata/cgo/cgo2.go12
-rw-r--r--libgo/go/cmd/vet/testdata/cgo/cgo3.go13
-rw-r--r--libgo/go/cmd/vet/testdata/cgo/cgo4.go15
-rw-r--r--libgo/go/cmd/vet/testdata/composite.go120
-rw-r--r--libgo/go/cmd/vet/testdata/copylock.go188
-rw-r--r--libgo/go/cmd/vet/testdata/copylock_func.go136
-rw-r--r--libgo/go/cmd/vet/testdata/copylock_range.go67
-rw-r--r--libgo/go/cmd/vet/testdata/deadcode.go2134
-rw-r--r--libgo/go/cmd/vet/testdata/divergent/buf.go17
-rw-r--r--libgo/go/cmd/vet/testdata/divergent/buf_test.go35
-rw-r--r--libgo/go/cmd/vet/testdata/httpresponse.go85
-rw-r--r--libgo/go/cmd/vet/testdata/incomplete/examples_test.go33
-rw-r--r--libgo/go/cmd/vet/testdata/lostcancel.go155
-rw-r--r--libgo/go/cmd/vet/testdata/nilfunc.go35
-rw-r--r--libgo/go/cmd/vet/testdata/rangeloop.go90
-rw-r--r--libgo/go/cmd/vet/testdata/shadow.go59
-rw-r--r--libgo/go/cmd/vet/testdata/shift.go162
-rw-r--r--libgo/go/cmd/vet/testdata/src/asm/asm.go9
-rw-r--r--libgo/go/cmd/vet/testdata/src/asm/asm1.s8
-rw-r--r--libgo/go/cmd/vet/testdata/src/assign/assign.go (renamed from libgo/go/cmd/vet/testdata/assign.go)2
-rw-r--r--libgo/go/cmd/vet/testdata/src/atomic/atomic.go14
-rw-r--r--libgo/go/cmd/vet/testdata/src/bool/bool.go14
-rw-r--r--libgo/go/cmd/vet/testdata/src/buildtag/buildtag.go (renamed from libgo/go/cmd/vet/testdata/buildtag/buildtag.go)0
-rw-r--r--libgo/go/cmd/vet/testdata/src/cgo/cgo.go18
-rw-r--r--libgo/go/cmd/vet/testdata/src/composite/composite.go24
-rw-r--r--libgo/go/cmd/vet/testdata/src/copylock/copylock.go11
-rw-r--r--libgo/go/cmd/vet/testdata/src/deadcode/deadcode.go14
-rw-r--r--libgo/go/cmd/vet/testdata/src/httpresponse/httpresponse.go22
-rw-r--r--libgo/go/cmd/vet/testdata/src/lostcancel/lostcancel.go14
-rw-r--r--libgo/go/cmd/vet/testdata/src/method/method.go (renamed from libgo/go/cmd/vet/testdata/method.go)14
-rw-r--r--libgo/go/cmd/vet/testdata/src/nilfunc/nilfunc.go13
-rw-r--r--libgo/go/cmd/vet/testdata/src/print/print.go (renamed from libgo/go/cmd/vet/testdata/print.go)128
-rw-r--r--libgo/go/cmd/vet/testdata/src/rangeloop/rangeloop.go17
-rw-r--r--libgo/go/cmd/vet/testdata/src/shift/shift.go13
-rw-r--r--libgo/go/cmd/vet/testdata/src/structtag/structtag.go11
-rw-r--r--libgo/go/cmd/vet/testdata/src/tagtest/file1.go (renamed from libgo/go/cmd/vet/testdata/tagtest/file1.go)3
-rw-r--r--libgo/go/cmd/vet/testdata/src/tagtest/file2.go (renamed from libgo/go/cmd/vet/testdata/tagtest/file2.go)5
-rw-r--r--libgo/go/cmd/vet/testdata/src/testingpkg/tests.go (renamed from libgo/go/cmd/vet/testdata/testingpkg/tests.go)0
-rw-r--r--libgo/go/cmd/vet/testdata/src/testingpkg/tests_test.go3
-rw-r--r--libgo/go/cmd/vet/testdata/src/unmarshal/unmarshal.go18
-rw-r--r--libgo/go/cmd/vet/testdata/src/unsafeptr/unsafeptr.go14
-rw-r--r--libgo/go/cmd/vet/testdata/src/unused/unused.go13
-rw-r--r--libgo/go/cmd/vet/testdata/structtag.go102
-rw-r--r--libgo/go/cmd/vet/testdata/testingpkg/tests_test.go74
-rw-r--r--libgo/go/cmd/vet/testdata/unsafeptr.go63
-rw-r--r--libgo/go/cmd/vet/testdata/unused.go29
-rw-r--r--libgo/go/cmd/vet/tests.go187
-rw-r--r--libgo/go/cmd/vet/types.go313
-rw-r--r--libgo/go/cmd/vet/unsafeptr.go97
-rw-r--r--libgo/go/cmd/vet/unused.go93
-rw-r--r--libgo/go/cmd/vet/vet_test.go215
225 files changed, 5494 insertions, 14219 deletions
diff --git a/libgo/go/cmd/cgo/ast.go b/libgo/go/cmd/cgo/ast.go
index 4462136bf4b..83d727a8a5d 100644
--- a/libgo/go/cmd/cgo/ast.go
+++ b/libgo/go/cmd/cgo/ast.go
@@ -145,6 +145,7 @@ func (f *File) ParseGo(name string, src []byte) {
if f.Ref == nil {
f.Ref = make([]*Ref, 0, 8)
}
+ f.walk(ast2, ctxProg, (*File).validateIdents)
f.walk(ast2, ctxProg, (*File).saveExprs)
// Accumulate exported functions.
@@ -181,6 +182,14 @@ func commentText(g *ast.CommentGroup) string {
return strings.Join(pieces, "")
}
+func (f *File) validateIdents(x interface{}, context astContext) {
+ if x, ok := x.(*ast.Ident); ok {
+ if f.isMangledName(x.Name) {
+ error_(x.Pos(), "identifier %q may conflict with identifiers generated by cgo", x.Name)
+ }
+ }
+}
+
// Save various references we are going to need later.
func (f *File) saveExprs(x interface{}, context astContext) {
switch x := x.(type) {
@@ -191,6 +200,18 @@ func (f *File) saveExprs(x interface{}, context astContext) {
}
case *ast.CallExpr:
f.saveCall(x, context)
+ case *ast.GenDecl:
+ if x.Tok == token.CONST {
+ for _, spec := range x.Specs {
+ vs := spec.(*ast.ValueSpec)
+ if vs.Type == nil {
+ for _, name := range spec.(*ast.ValueSpec).Names {
+ consts[name.Name] = true
+ }
+ }
+ }
+ }
+
}
}
diff --git a/libgo/go/cmd/cgo/doc.go b/libgo/go/cmd/cgo/doc.go
index 157cd94d653..cceb33edbdb 100644
--- a/libgo/go/cmd/cgo/doc.go
+++ b/libgo/go/cmd/cgo/doc.go
@@ -413,6 +413,8 @@ type in Go are instead represented by a uintptr. Those include:
jobjectArray
jweak
+3. The EGLDisplay type from the EGL API.
+
These types are uintptr on the Go side because they would otherwise
confuse the Go garbage collector; they are sometimes not really
pointers but data structures encoded in a pointer type. All operations
@@ -427,6 +429,11 @@ from Go 1.9 and earlier, use the cftype or jni rewrites in the Go fix tool:
It will replace nil with 0 in the appropriate places.
+The EGLDisplay case were introduced in Go 1.12. Use the egl rewrite
+to auto-update code from Go 1.11 and earlier:
+
+ go tool fix -r egl <pkg>
+
Using cgo directly
Usage:
@@ -827,6 +834,10 @@ The directives are:
possibly version in the dynamic library, and the optional "<library>"
names the specific library where the symbol should be found.
+ On AIX, the library pattern is slightly different. It must be
+ "lib.a/obj.o" with obj.o the member of this library exporting
+ this symbol.
+
In the <remote>, # or @ can be used to introduce a symbol version.
Examples:
diff --git a/libgo/go/cmd/cgo/gcc.go b/libgo/go/cmd/cgo/gcc.go
index 2a2d0080d5e..a8429725209 100644
--- a/libgo/go/cmd/cgo/gcc.go
+++ b/libgo/go/cmd/cgo/gcc.go
@@ -13,7 +13,6 @@ import (
"debug/elf"
"debug/macho"
"debug/pe"
- "debug/xcoff"
"encoding/binary"
"errors"
"flag"
@@ -21,6 +20,7 @@ import (
"go/ast"
"go/parser"
"go/token"
+ "internal/xcoff"
"math"
"os"
"strconv"
@@ -89,8 +89,14 @@ func (f *File) DiscardCgoDirectives() {
// _cgo_flags file for the build system to use.
func (p *Package) addToFlag(flag string, args []string) {
if flag == "CFLAGS" {
- // We'll need these when preprocessing for dwarf information.
- p.GccOptions = append(p.GccOptions, args...)
+ // We'll also need these when preprocessing for dwarf information.
+ // However, discard any -g options: we need to be able
+ // to parse the debug info, so stick to what we expect.
+ for _, arg := range args {
+ if !strings.HasPrefix(arg, "-g") {
+ p.GccOptions = append(p.GccOptions, arg)
+ }
+ }
}
skip := false
@@ -182,6 +188,10 @@ func (p *Package) Translate(f *File) {
// Convert C.ulong to C.unsigned long, etc.
cref.Name.C = cname(cref.Name.Go)
}
+
+ var conv typeConv
+ conv.Init(p.PtrSize, p.IntSize)
+
p.loadDefines(f)
p.typedefs = map[string]bool{}
p.typedefList = nil
@@ -189,15 +199,17 @@ func (p *Package) Translate(f *File) {
for len(p.typedefs) > numTypedefs {
numTypedefs = len(p.typedefs)
// Also ask about any typedefs we've seen so far.
- for _, a := range p.typedefList {
- f.Name[a] = &Name{
- Go: a,
- C: a,
+ for _, info := range p.typedefList {
+ n := &Name{
+ Go: info.typedef,
+ C: info.typedef,
}
+ f.Name[info.typedef] = n
+ f.NamePos[n] = info.pos
}
needType := p.guessKinds(f)
if len(needType) > 0 {
- p.loadDWARF(f, needType)
+ p.loadDWARF(f, &conv, needType)
}
// In godefs mode we're OK with the typedefs, which
@@ -207,6 +219,7 @@ func (p *Package) Translate(f *File) {
break
}
}
+ p.prepareNames(f)
if p.rewriteCalls(f) {
// Add `import _cgo_unsafe "unsafe"` after the package statement.
f.Edit.Insert(f.offset(f.AST.Name.End()), "; import _cgo_unsafe \"unsafe\"")
@@ -491,7 +504,7 @@ func (p *Package) guessKinds(f *File) []*Name {
// loadDWARF parses the DWARF debug information generated
// by gcc to learn the details of the constants, variables, and types
// being referred to as C.xxx.
-func (p *Package) loadDWARF(f *File, names []*Name) {
+func (p *Package) loadDWARF(f *File, conv *typeConv, names []*Name) {
// Extract the types from the DWARF section of an object
// from a well-formed C program. Gcc only generates DWARF info
// for symbols in the object file, so it is not enough to print the
@@ -590,7 +603,7 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
fatalf("malformed __cgo__ name: %s", name)
}
types[i] = t.Type
- p.recordTypedefs(t.Type)
+ p.recordTypedefs(t.Type, f.NamePos[names[i]])
}
if e.Tag != dwarf.TagCompileUnit {
r.SkipChildren()
@@ -598,8 +611,6 @@ 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
@@ -658,10 +669,11 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
}
// recordTypedefs remembers in p.typedefs all the typedefs used in dtypes and its children.
-func (p *Package) recordTypedefs(dtype dwarf.Type) {
- p.recordTypedefs1(dtype, map[dwarf.Type]bool{})
+func (p *Package) recordTypedefs(dtype dwarf.Type, pos token.Pos) {
+ p.recordTypedefs1(dtype, pos, map[dwarf.Type]bool{})
}
-func (p *Package) recordTypedefs1(dtype dwarf.Type, visited map[dwarf.Type]bool) {
+
+func (p *Package) recordTypedefs1(dtype dwarf.Type, pos token.Pos, visited map[dwarf.Type]bool) {
if dtype == nil {
return
}
@@ -677,24 +689,45 @@ func (p *Package) recordTypedefs1(dtype dwarf.Type, visited map[dwarf.Type]bool)
}
if !p.typedefs[dt.Name] {
p.typedefs[dt.Name] = true
- p.typedefList = append(p.typedefList, dt.Name)
- p.recordTypedefs1(dt.Type, visited)
+ p.typedefList = append(p.typedefList, typedefInfo{dt.Name, pos})
+ p.recordTypedefs1(dt.Type, pos, visited)
}
case *dwarf.PtrType:
- p.recordTypedefs1(dt.Type, visited)
+ p.recordTypedefs1(dt.Type, pos, visited)
case *dwarf.ArrayType:
- p.recordTypedefs1(dt.Type, visited)
+ p.recordTypedefs1(dt.Type, pos, visited)
case *dwarf.QualType:
- p.recordTypedefs1(dt.Type, visited)
+ p.recordTypedefs1(dt.Type, pos, visited)
case *dwarf.FuncType:
- p.recordTypedefs1(dt.ReturnType, visited)
+ p.recordTypedefs1(dt.ReturnType, pos, visited)
for _, a := range dt.ParamType {
- p.recordTypedefs1(a, visited)
+ p.recordTypedefs1(a, pos, visited)
}
case *dwarf.StructType:
for _, f := range dt.Field {
- p.recordTypedefs1(f.Type, visited)
+ p.recordTypedefs1(f.Type, pos, visited)
+ }
+ }
+}
+
+// prepareNames finalizes the Kind field of not-type names and sets
+// the mangled name of all names.
+func (p *Package) prepareNames(f *File) {
+ for _, n := range f.Name {
+ if n.Kind == "not-type" {
+ if n.Define == "" {
+ n.Kind = "var"
+ } else {
+ n.Kind = "macro"
+ n.FuncType = &FuncType{
+ Result: n.Type,
+ Go: &ast.FuncType{
+ Results: &ast.FieldList{List: []*ast.Field{{Type: n.Type.Go}}},
+ },
+ }
+ }
}
+ p.mangleName(n)
}
}
@@ -712,24 +745,37 @@ func (p *Package) mangleName(n *Name) {
n.Mangle = prefix + n.Kind + "_" + n.Go
}
+func (f *File) isMangledName(s string) bool {
+ prefix := "_C"
+ if strings.HasPrefix(s, prefix) {
+ t := s[len(prefix):]
+ for _, k := range nameKinds {
+ if strings.HasPrefix(t, k+"_") {
+ return true
+ }
+ }
+ }
+ return false
+}
+
// rewriteCalls rewrites all calls that pass pointers to check that
// they follow the rules for passing pointers between Go and C.
-// This returns whether the package needs to import unsafe as _cgo_unsafe.
+// This reports whether the package needs to import unsafe as _cgo_unsafe.
func (p *Package) rewriteCalls(f *File) bool {
needsUnsafe := false
+ // Walk backward so that in C.f1(C.f2()) we rewrite C.f2 first.
for _, call := range f.Calls {
- // This is a call to C.xxx; set goname to "xxx".
- goname := call.Call.Fun.(*ast.SelectorExpr).Sel.Name
- if goname == "malloc" {
- continue
- }
- name := f.Name[goname]
- if name.Kind != "func" {
- // Probably a type conversion.
+ if call.Done {
continue
}
- if p.rewriteCall(f, call, name) {
- needsUnsafe = true
+ start := f.offset(call.Call.Pos())
+ end := f.offset(call.Call.End())
+ str, nu := p.rewriteCall(f, call)
+ if str != "" {
+ f.Edit.Replace(start, end, str)
+ if nu {
+ needsUnsafe = true
+ }
}
}
return needsUnsafe
@@ -739,162 +785,206 @@ func (p *Package) rewriteCalls(f *File) bool {
// If any pointer checks are required, we rewrite the call into a
// function literal that calls _cgoCheckPointer for each pointer
// argument and then calls the original function.
-// This returns whether the package needs to import unsafe as _cgo_unsafe.
-func (p *Package) rewriteCall(f *File, call *Call, name *Name) bool {
+// This returns the rewritten call and whether the package needs to
+// import unsafe as _cgo_unsafe.
+// If it returns the empty string, the call did not need to be rewritten.
+func (p *Package) rewriteCall(f *File, call *Call) (string, bool) {
+ // This is a call to C.xxx; set goname to "xxx".
+ // It may have already been mangled by rewriteName.
+ var goname string
+ switch fun := call.Call.Fun.(type) {
+ case *ast.SelectorExpr:
+ goname = fun.Sel.Name
+ case *ast.Ident:
+ goname = strings.TrimPrefix(fun.Name, "_C2func_")
+ goname = strings.TrimPrefix(goname, "_Cfunc_")
+ }
+ if goname == "" || goname == "malloc" {
+ return "", false
+ }
+ name := f.Name[goname]
+ if name == nil || name.Kind != "func" {
+ // Probably a type conversion.
+ return "", false
+ }
+
+ params := name.FuncType.Params
+ args := call.Call.Args
+
// Avoid a crash if the number of arguments is
// less than the number of parameters.
// This will be caught when the generated file is compiled.
- if len(call.Call.Args) < len(name.FuncType.Params) {
- return false
+ if len(args) < len(params) {
+ return "", false
}
any := false
- for i, param := range name.FuncType.Params {
- if p.needsPointerCheck(f, param.Go, call.Call.Args[i]) {
+ for i, param := range params {
+ if p.needsPointerCheck(f, param.Go, args[i]) {
any = true
break
}
}
if !any {
- return false
+ return "", false
}
// We need to rewrite this call.
//
- // We are going to rewrite C.f(p) to
- // func (_cgo0 ptype) {
+ // Rewrite C.f(p) to
+ // func() {
+ // _cgo0 := p
// _cgoCheckPointer(_cgo0)
// C.f(_cgo0)
- // }(p)
- // Using a function literal like this lets us do correct
- // argument type checking, and works correctly if the call is
- // deferred.
+ // }()
+ // Using a function literal like this lets us evaluate the
+ // function arguments only once while doing pointer checks.
+ // This is particularly useful when passing additional arguments
+ // to _cgoCheckPointer, as done in checkIndex and checkAddr.
+ //
+ // When the function argument is a conversion to unsafe.Pointer,
+ // we unwrap the conversion before checking the pointer,
+ // and then wrap again when calling C.f. This lets us check
+ // the real type of the pointer in some cases. See issue #25941.
+ //
+ // When the call to C.f is deferred, we use an additional function
+ // literal to evaluate the arguments at the right time.
+ // defer func() func() {
+ // _cgo0 := p
+ // return func() {
+ // _cgoCheckPointer(_cgo0)
+ // C.f(_cgo0)
+ // }
+ // }()()
+ // This works because the defer statement evaluates the first
+ // function literal in order to get the function to call.
+
+ var sb bytes.Buffer
+ sb.WriteString("func() ")
+ if call.Deferred {
+ sb.WriteString("func() ")
+ }
+
needsUnsafe := false
- params := make([]*ast.Field, len(name.FuncType.Params))
- nargs := make([]ast.Expr, len(name.FuncType.Params))
- var stmts []ast.Stmt
- for i, param := range name.FuncType.Params {
- // params is going to become the parameters of the
- // function literal.
- // nargs is going to become the list of arguments made
- // by the call within the function literal.
- // nparam is the parameter of the function literal that
- // corresponds to param.
-
- origArg := call.Call.Args[i]
- nparam := ast.NewIdent(fmt.Sprintf("_cgo%d", i))
- nargs[i] = nparam
-
- // The Go version of the C type might use unsafe.Pointer,
- // but the file might not import unsafe.
- // Rewrite the Go type if necessary to use _cgo_unsafe.
- ptype := p.rewriteUnsafe(param.Go)
- if ptype != param.Go {
- needsUnsafe = true
+ result := false
+ twoResults := false
+ if !call.Deferred {
+ // Check whether this call expects two results.
+ for _, ref := range f.Ref {
+ if ref.Expr != &call.Call.Fun {
+ continue
+ }
+ if ref.Context == ctxCall2 {
+ sb.WriteString("(")
+ result = true
+ twoResults = true
+ }
+ break
}
- params[i] = &ast.Field{
- Names: []*ast.Ident{nparam},
- Type: ptype,
+ // Add the result type, if any.
+ if name.FuncType.Result != nil {
+ rtype := p.rewriteUnsafe(name.FuncType.Result.Go)
+ if rtype != name.FuncType.Result.Go {
+ needsUnsafe = true
+ }
+ sb.WriteString(gofmtLine(rtype))
+ result = true
}
- if !p.needsPointerCheck(f, param.Go, origArg) {
- continue
+ // Add the second result type, if any.
+ if twoResults {
+ if name.FuncType.Result == nil {
+ // An explicit void result looks odd but it
+ // seems to be how cgo has worked historically.
+ sb.WriteString("_Ctype_void")
+ }
+ sb.WriteString(", error)")
}
+ }
- // Run the cgo pointer checks on nparam.
+ sb.WriteString("{ ")
- // Change the function literal to call the real function
- // with the parameter passed through _cgoCheckPointer.
- c := &ast.CallExpr{
- Fun: ast.NewIdent("_cgoCheckPointer"),
- Args: []ast.Expr{
- nparam,
- },
+ // Define _cgoN for each argument value.
+ // Write _cgoCheckPointer calls to sbCheck.
+ var sbCheck bytes.Buffer
+ for i, param := range params {
+ origArg := args[i]
+ arg, nu := p.mangle(f, &args[i])
+ if nu {
+ needsUnsafe = true
}
- // Add optional additional arguments for an address
- // expression.
- c.Args = p.checkAddrArgs(f, c.Args, origArg)
+ // Explicitly convert untyped constants to the
+ // parameter type, to avoid a type mismatch.
+ if p.isConst(f, arg) {
+ ptype := p.rewriteUnsafe(param.Go)
+ if ptype != param.Go {
+ needsUnsafe = true
+ }
+ arg = &ast.CallExpr{
+ Fun: ptype,
+ Args: []ast.Expr{arg},
+ }
+ }
+
+ if !p.needsPointerCheck(f, param.Go, args[i]) {
+ fmt.Fprintf(&sb, "_cgo%d := %s; ", i, gofmtPos(arg, origArg.Pos()))
+ continue
+ }
- stmt := &ast.ExprStmt{
- X: c,
+ // Check for &a[i].
+ if p.checkIndex(&sb, &sbCheck, arg, i) {
+ continue
+ }
+
+ // Check for &x.
+ if p.checkAddr(&sb, &sbCheck, arg, i) {
+ continue
}
- stmts = append(stmts, stmt)
+
+ fmt.Fprintf(&sb, "_cgo%d := %s; ", i, gofmtPos(arg, origArg.Pos()))
+ fmt.Fprintf(&sbCheck, "_cgoCheckPointer(_cgo%d); ", i)
}
- const cgoMarker = "__cgo__###__marker__"
- fcall := &ast.CallExpr{
- Fun: ast.NewIdent(cgoMarker),
- Args: nargs,
+ if call.Deferred {
+ sb.WriteString("return func() { ")
}
- ftype := &ast.FuncType{
- Params: &ast.FieldList{
- List: params,
- },
+
+ // Write out the calls to _cgoCheckPointer.
+ sb.WriteString(sbCheck.String())
+
+ if result {
+ sb.WriteString("return ")
}
- if name.FuncType.Result != nil {
- rtype := p.rewriteUnsafe(name.FuncType.Result.Go)
- if rtype != name.FuncType.Result.Go {
- needsUnsafe = true
- }
- ftype.Results = &ast.FieldList{
- List: []*ast.Field{
- &ast.Field{
- Type: rtype,
- },
- },
- }
- }
-
- // If this call expects two results, we have to
- // adjust the results of the function we generated.
- for _, ref := range f.Ref {
- if ref.Expr == &call.Call.Fun && ref.Context == ctxCall2 {
- if ftype.Results == nil {
- // An explicit void argument
- // looks odd but it seems to
- // be how cgo has worked historically.
- ftype.Results = &ast.FieldList{
- List: []*ast.Field{
- &ast.Field{
- Type: ast.NewIdent("_Ctype_void"),
- },
- },
- }
- }
- ftype.Results.List = append(ftype.Results.List,
- &ast.Field{
- Type: ast.NewIdent("error"),
- })
- }
+
+ m, nu := p.mangle(f, &call.Call.Fun)
+ if nu {
+ needsUnsafe = true
}
+ sb.WriteString(gofmtLine(m))
- var fbody ast.Stmt
- if ftype.Results == nil {
- fbody = &ast.ExprStmt{
- X: fcall,
- }
- } else {
- fbody = &ast.ReturnStmt{
- Results: []ast.Expr{fcall},
+ sb.WriteString("(")
+ for i := range params {
+ if i > 0 {
+ sb.WriteString(", ")
}
+ fmt.Fprintf(&sb, "_cgo%d", i)
}
- lit := &ast.FuncLit{
- Type: ftype,
- Body: &ast.BlockStmt{
- List: append(stmts, fbody),
- },
+ sb.WriteString("); ")
+ if call.Deferred {
+ sb.WriteString("}")
}
- text := strings.Replace(gofmt(lit), "\n", ";", -1)
- repl := strings.Split(text, cgoMarker)
- f.Edit.Insert(f.offset(call.Call.Fun.Pos()), repl[0])
- f.Edit.Insert(f.offset(call.Call.Fun.End()), repl[1])
+ sb.WriteString("}")
+ if call.Deferred {
+ sb.WriteString("()")
+ }
+ sb.WriteString("()")
- return needsUnsafe
+ return sb.String(), needsUnsafe
}
-// needsPointerCheck returns whether the type t needs a pointer check.
+// needsPointerCheck reports whether the type t needs a pointer check.
// This is true if t is a pointer and if the value to which it points
// might contain a pointer.
func (p *Package) needsPointerCheck(f *File, t ast.Expr, arg ast.Expr) bool {
@@ -911,7 +1001,7 @@ func (p *Package) needsPointerCheck(f *File, t ast.Expr, arg ast.Expr) bool {
// hasPointer is used by needsPointerCheck. If top is true it returns
// whether t is or contains a pointer that might point to a pointer.
-// If top is false it returns whether t is or contains a pointer.
+// If top is false it reports whether t is or contains a pointer.
// f may be nil.
func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
switch t := t.(type) {
@@ -998,19 +1088,68 @@ func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
}
}
-// checkAddrArgs tries to add arguments to the call of
-// _cgoCheckPointer when the argument is an address expression. We
-// pass true to mean that the argument is an address operation of
-// something other than a slice index, which means that it's only
-// necessary to check the specific element pointed to, not the entire
-// object. This is for &s.f, where f is a field in a struct. We can
-// pass a slice or array, meaning that we should check the entire
-// slice or array but need not check any other part of the object.
-// This is for &s.a[i], where we need to check all of a. However, we
-// only pass the slice or array if we can refer to it without side
-// effects.
-func (p *Package) checkAddrArgs(f *File, args []ast.Expr, x ast.Expr) []ast.Expr {
+// mangle replaces references to C names in arg with the mangled names,
+// rewriting calls when it finds them.
+// It removes the corresponding references in f.Ref and f.Calls, so that we
+// don't try to do the replacement again in rewriteRef or rewriteCall.
+func (p *Package) mangle(f *File, arg *ast.Expr) (ast.Expr, bool) {
+ needsUnsafe := false
+ f.walk(arg, ctxExpr, func(f *File, arg interface{}, context astContext) {
+ px, ok := arg.(*ast.Expr)
+ if !ok {
+ return
+ }
+ sel, ok := (*px).(*ast.SelectorExpr)
+ if ok {
+ if l, ok := sel.X.(*ast.Ident); !ok || l.Name != "C" {
+ return
+ }
+
+ for _, r := range f.Ref {
+ if r.Expr == px {
+ *px = p.rewriteName(f, r)
+ r.Done = true
+ break
+ }
+ }
+
+ return
+ }
+
+ call, ok := (*px).(*ast.CallExpr)
+ if !ok {
+ return
+ }
+
+ for _, c := range f.Calls {
+ if !c.Done && c.Call.Lparen == call.Lparen {
+ cstr, nu := p.rewriteCall(f, c)
+ if cstr != "" {
+ // Smuggle the rewritten call through an ident.
+ *px = ast.NewIdent(cstr)
+ if nu {
+ needsUnsafe = true
+ }
+ c.Done = true
+ }
+ }
+ }
+ })
+ return *arg, needsUnsafe
+}
+
+// checkIndex checks whether arg has the form &a[i], possibly inside
+// type conversions. If so, it writes
+// _cgoIndexNN := a
+// _cgoNN := &cgoIndexNN[i] // with type conversions, if any
+// to sb, and writes
+// _cgoCheckPointer(_cgoNN, _cgoIndexNN)
+// to sbCheck, and returns true. This tells _cgoCheckPointer to check
+// the complete contents of the slice or array being indexed, but no
+// other part of the memory allocation.
+func (p *Package) checkIndex(sb, sbCheck *bytes.Buffer, arg ast.Expr, i int) bool {
// Strip type conversions.
+ x := arg
for {
c, ok := x.(*ast.CallExpr)
if !ok || len(c.Args) != 1 || !p.isType(c.Fun) {
@@ -1020,40 +1159,63 @@ func (p *Package) checkAddrArgs(f *File, args []ast.Expr, x ast.Expr) []ast.Expr
}
u, ok := x.(*ast.UnaryExpr)
if !ok || u.Op != token.AND {
- return args
+ return false
}
index, ok := u.X.(*ast.IndexExpr)
if !ok {
- // This is the address of something that is not an
- // index expression. We only need to examine the
- // single value to which it points.
- // TODO: what if true is shadowed?
- return append(args, ast.NewIdent("true"))
- }
- if !p.hasSideEffects(f, index.X) {
- // Examine the entire slice.
- return append(args, index.X)
- }
- // Treat the pointer as unknown.
- return args
+ return false
+ }
+
+ fmt.Fprintf(sb, "_cgoIndex%d := %s; ", i, gofmtPos(index.X, index.X.Pos()))
+ origX := index.X
+ index.X = ast.NewIdent(fmt.Sprintf("_cgoIndex%d", i))
+ fmt.Fprintf(sb, "_cgo%d := %s; ", i, gofmtPos(arg, arg.Pos()))
+ index.X = origX
+
+ fmt.Fprintf(sbCheck, "_cgoCheckPointer(_cgo%d, _cgoIndex%d); ", i, i)
+
+ return true
}
-// hasSideEffects returns whether the expression x has any side
-// effects. x is an expression, not a statement, so the only side
-// effect is a function call.
-func (p *Package) hasSideEffects(f *File, x ast.Expr) bool {
- found := false
- f.walk(x, ctxExpr,
- func(f *File, x interface{}, context astContext) {
- switch x.(type) {
- case *ast.CallExpr:
- found = true
- }
- })
- return found
+// checkAddr checks whether arg has the form &x, possibly inside type
+// conversions. If so, it writes
+// _cgoBaseNN := &x
+// _cgoNN := _cgoBaseNN // with type conversions, if any
+// to sb, and writes
+// _cgoCheckPointer(_cgoBaseNN, true)
+// to sbCheck, and returns true. This tells _cgoCheckPointer to check
+// just the contents of the pointer being passed, not any other part
+// of the memory allocation. This is run after checkIndex, which looks
+// for the special case of &a[i], which requires different checks.
+func (p *Package) checkAddr(sb, sbCheck *bytes.Buffer, arg ast.Expr, i int) bool {
+ // Strip type conversions.
+ px := &arg
+ for {
+ c, ok := (*px).(*ast.CallExpr)
+ if !ok || len(c.Args) != 1 || !p.isType(c.Fun) {
+ break
+ }
+ px = &c.Args[0]
+ }
+ if u, ok := (*px).(*ast.UnaryExpr); !ok || u.Op != token.AND {
+ return false
+ }
+
+ fmt.Fprintf(sb, "_cgoBase%d := %s; ", i, gofmtPos(*px, (*px).Pos()))
+
+ origX := *px
+ *px = ast.NewIdent(fmt.Sprintf("_cgoBase%d", i))
+ fmt.Fprintf(sb, "_cgo%d := %s; ", i, gofmtPos(arg, arg.Pos()))
+ *px = origX
+
+ // Use "0 == 0" to do the right thing in the unlikely event
+ // that "true" is shadowed.
+ fmt.Fprintf(sbCheck, "_cgoCheckPointer(_cgoBase%d, 0 == 0); ", i)
+
+ return true
}
-// isType returns whether the expression is definitely a type.
+// isType reports whether the expression is definitely a type.
// This is conservative--it returns false for an unknown identifier.
func (p *Package) isType(t ast.Expr) bool {
switch t := t.(type) {
@@ -1082,6 +1244,9 @@ func (p *Package) isType(t ast.Expr) bool {
return true
}
+ if strings.HasPrefix(t.Name, "_Ctype_") {
+ return true
+ }
case *ast.StarExpr:
return p.isType(t.X)
case *ast.ArrayType, *ast.StructType, *ast.FuncType, *ast.InterfaceType,
@@ -1092,6 +1257,47 @@ func (p *Package) isType(t ast.Expr) bool {
return false
}
+// isConst reports whether x is an untyped constant expression.
+func (p *Package) isConst(f *File, x ast.Expr) bool {
+ switch x := x.(type) {
+ case *ast.BasicLit:
+ return true
+ case *ast.SelectorExpr:
+ id, ok := x.X.(*ast.Ident)
+ if !ok || id.Name != "C" {
+ return false
+ }
+ name := f.Name[x.Sel.Name]
+ if name != nil {
+ return name.IsConst()
+ }
+ case *ast.Ident:
+ return x.Name == "nil" ||
+ strings.HasPrefix(x.Name, "_Ciconst_") ||
+ strings.HasPrefix(x.Name, "_Cfconst_") ||
+ strings.HasPrefix(x.Name, "_Csconst_") ||
+ consts[x.Name]
+ case *ast.UnaryExpr:
+ return p.isConst(f, x.X)
+ case *ast.BinaryExpr:
+ return p.isConst(f, x.X) && p.isConst(f, x.Y)
+ case *ast.ParenExpr:
+ return p.isConst(f, x.X)
+ case *ast.CallExpr:
+ // Calling the builtin function complex on two untyped
+ // constants returns an untyped constant.
+ // TODO: It's possible to construct a case that will
+ // erroneously succeed if there is a local function
+ // named "complex", shadowing the builtin, that returns
+ // a numeric type. I can't think of any cases that will
+ // erroneously fail.
+ if id, ok := x.Fun.(*ast.Ident); ok && id.Name == "complex" && len(x.Args) == 2 {
+ return p.isConst(f, x.Args[0]) && p.isConst(f, x.Args[1])
+ }
+ }
+ return false
+}
+
// rewriteUnsafe returns a version of t with references to unsafe.Pointer
// rewritten to use _cgo_unsafe.Pointer instead.
func (p *Package) rewriteUnsafe(t ast.Expr) ast.Expr {
@@ -1150,24 +1356,7 @@ func (p *Package) rewriteRef(f *File) {
// code for them.
functions := make(map[string]bool)
- // Assign mangled names.
for _, n := range f.Name {
- if n.Kind == "not-type" {
- if n.Define == "" {
- n.Kind = "var"
- } else {
- n.Kind = "macro"
- n.FuncType = &FuncType{
- Result: n.Type,
- Go: &ast.FuncType{
- Results: &ast.FieldList{List: []*ast.Field{{Type: n.Type.Go}}},
- },
- }
- }
- }
- if n.Mangle == "" {
- p.mangleName(n)
- }
if n.Kind == "func" {
functions[n.Go] = false
}
@@ -1181,104 +1370,16 @@ func (p *Package) rewriteRef(f *File) {
if r.Name.IsConst() && r.Name.Const == "" {
error_(r.Pos(), "unable to find value of constant C.%s", fixGo(r.Name.Go))
}
- var expr ast.Expr = ast.NewIdent(r.Name.Mangle) // default
- switch r.Context {
- case ctxCall, ctxCall2:
- if r.Name.Kind != "func" {
- if r.Name.Kind == "type" {
- r.Context = ctxType
- if r.Name.Type == nil {
- error_(r.Pos(), "invalid conversion to C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
- break
- }
- expr = r.Name.Type.Go
- break
- }
- error_(r.Pos(), "call of non-function C.%s", fixGo(r.Name.Go))
- break
- }
- functions[r.Name.Go] = true
- if r.Context == ctxCall2 {
- if r.Name.Go == "_CMalloc" {
- error_(r.Pos(), "no two-result form for C.malloc")
- break
- }
- // Invent new Name for the two-result function.
- n := f.Name["2"+r.Name.Go]
- if n == nil {
- n = new(Name)
- *n = *r.Name
- n.AddError = true
- n.Mangle = "_C2func_" + n.Go
- f.Name["2"+r.Name.Go] = n
- }
- expr = ast.NewIdent(n.Mangle)
- r.Name = n
- break
- }
- case ctxExpr:
- switch r.Name.Kind {
- case "func":
- if builtinDefs[r.Name.C] != "" {
- error_(r.Pos(), "use of builtin '%s' not in function call", fixGo(r.Name.C))
- }
- // Function is being used in an expression, to e.g. pass around a C function pointer.
- // Create a new Name for this Ref which causes the variable to be declared in Go land.
- fpName := "fp_" + r.Name.Go
- name := f.Name[fpName]
- if name == nil {
- name = &Name{
- Go: fpName,
- C: r.Name.C,
- Kind: "fpvar",
- Type: &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*"), Go: ast.NewIdent("unsafe.Pointer")},
- }
- p.mangleName(name)
- f.Name[fpName] = name
- }
- r.Name = name
- // Rewrite into call to _Cgo_ptr to prevent assignments. The _Cgo_ptr
- // function is defined in out.go and simply returns its argument. See
- // issue 7757.
- expr = &ast.CallExpr{
- Fun: &ast.Ident{NamePos: (*r.Expr).Pos(), Name: "_Cgo_ptr"},
- Args: []ast.Expr{ast.NewIdent(name.Mangle)},
- }
- case "type":
- // Okay - might be new(T)
- if r.Name.Type == nil {
- error_(r.Pos(), "expression C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
- break
- }
- expr = r.Name.Type.Go
- case "var":
- expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
- case "macro":
- expr = &ast.CallExpr{Fun: expr}
- }
- case ctxSelector:
- if r.Name.Kind == "var" {
- expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
- } else {
- error_(r.Pos(), "only C variables allowed in selector expression %s", fixGo(r.Name.Go))
- }
- case ctxType:
- if r.Name.Kind != "type" {
- error_(r.Pos(), "expression C.%s used as type", fixGo(r.Name.Go))
- } else if r.Name.Type == nil {
- // Use of C.enum_x, C.struct_x or C.union_x without C definition.
- // GCC won't raise an error when using pointers to such unknown types.
- error_(r.Pos(), "type C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
- } else {
- expr = r.Name.Type.Go
- }
- default:
- if r.Name.Kind == "func" {
- error_(r.Pos(), "must call C.%s", fixGo(r.Name.Go))
+ if r.Name.Kind == "func" {
+ switch r.Context {
+ case ctxCall, ctxCall2:
+ functions[r.Name.Go] = true
}
}
+ expr := p.rewriteName(f, r)
+
if *godefs {
// Substitute definition for mangled type name.
if id, ok := expr.(*ast.Ident); ok {
@@ -1295,8 +1396,7 @@ func (p *Package) rewriteRef(f *File) {
// in case expression being replaced is first on line.
// See golang.org/issue/6563.
pos := (*r.Expr).Pos()
- switch x := expr.(type) {
- case *ast.Ident:
+ if x, ok := expr.(*ast.Ident); ok {
expr = &ast.Ident{NamePos: pos, Name: x.Name}
}
@@ -1306,11 +1406,26 @@ func (p *Package) rewriteRef(f *File) {
*r.Expr = expr
// Record source-level edit for cgo output.
- repl := gofmt(expr)
- if r.Name.Kind != "type" {
- repl = "(" + repl + ")"
+ if !r.Done {
+ // Prepend a space in case the earlier code ends
+ // with '/', which would give us a "//" comment.
+ repl := " " + gofmtPos(expr, old.Pos())
+ end := fset.Position(old.End())
+ // Subtract 1 from the column if we are going to
+ // append a close parenthesis. That will set the
+ // correct column for the following characters.
+ sub := 0
+ if r.Name.Kind != "type" {
+ sub = 1
+ }
+ if end.Column > sub {
+ repl = fmt.Sprintf("%s /*line :%d:%d*/", repl, end.Line, end.Column-sub)
+ }
+ if r.Name.Kind != "type" {
+ repl = "(" + repl + ")"
+ }
+ f.Edit.Replace(f.offset(old.Pos()), f.offset(old.End()), repl)
}
- f.Edit.Replace(f.offset(old.Pos()), f.offset(old.End()), repl)
}
// Remove functions only used as expressions, so their respective
@@ -1322,6 +1437,118 @@ func (p *Package) rewriteRef(f *File) {
}
}
+// rewriteName returns the expression used to rewrite a reference.
+func (p *Package) rewriteName(f *File, r *Ref) ast.Expr {
+ var expr ast.Expr = ast.NewIdent(r.Name.Mangle) // default
+ switch r.Context {
+ case ctxCall, ctxCall2:
+ if r.Name.Kind != "func" {
+ if r.Name.Kind == "type" {
+ r.Context = ctxType
+ if r.Name.Type == nil {
+ error_(r.Pos(), "invalid conversion to C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
+ break
+ }
+ expr = r.Name.Type.Go
+ break
+ }
+ error_(r.Pos(), "call of non-function C.%s", fixGo(r.Name.Go))
+ break
+ }
+ if r.Context == ctxCall2 {
+ if r.Name.Go == "_CMalloc" {
+ error_(r.Pos(), "no two-result form for C.malloc")
+ break
+ }
+ // Invent new Name for the two-result function.
+ n := f.Name["2"+r.Name.Go]
+ if n == nil {
+ n = new(Name)
+ *n = *r.Name
+ n.AddError = true
+ n.Mangle = "_C2func_" + n.Go
+ f.Name["2"+r.Name.Go] = n
+ }
+ expr = ast.NewIdent(n.Mangle)
+ r.Name = n
+ break
+ }
+ case ctxExpr:
+ switch r.Name.Kind {
+ case "func":
+ if builtinDefs[r.Name.C] != "" {
+ error_(r.Pos(), "use of builtin '%s' not in function call", fixGo(r.Name.C))
+ }
+
+ // Function is being used in an expression, to e.g. pass around a C function pointer.
+ // Create a new Name for this Ref which causes the variable to be declared in Go land.
+ fpName := "fp_" + r.Name.Go
+ name := f.Name[fpName]
+ if name == nil {
+ name = &Name{
+ Go: fpName,
+ C: r.Name.C,
+ Kind: "fpvar",
+ Type: &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*"), Go: ast.NewIdent("unsafe.Pointer")},
+ }
+ p.mangleName(name)
+ f.Name[fpName] = name
+ }
+ r.Name = name
+ // Rewrite into call to _Cgo_ptr to prevent assignments. The _Cgo_ptr
+ // function is defined in out.go and simply returns its argument. See
+ // issue 7757.
+ expr = &ast.CallExpr{
+ Fun: &ast.Ident{NamePos: (*r.Expr).Pos(), Name: "_Cgo_ptr"},
+ Args: []ast.Expr{ast.NewIdent(name.Mangle)},
+ }
+ case "type":
+ // Okay - might be new(T)
+ if r.Name.Type == nil {
+ error_(r.Pos(), "expression C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
+ break
+ }
+ expr = r.Name.Type.Go
+ case "var":
+ expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
+ case "macro":
+ expr = &ast.CallExpr{Fun: expr}
+ }
+ case ctxSelector:
+ if r.Name.Kind == "var" {
+ expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
+ } else {
+ error_(r.Pos(), "only C variables allowed in selector expression %s", fixGo(r.Name.Go))
+ }
+ case ctxType:
+ if r.Name.Kind != "type" {
+ error_(r.Pos(), "expression C.%s used as type", fixGo(r.Name.Go))
+ } else if r.Name.Type == nil {
+ // Use of C.enum_x, C.struct_x or C.union_x without C definition.
+ // GCC won't raise an error when using pointers to such unknown types.
+ error_(r.Pos(), "type C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
+ } else {
+ expr = r.Name.Type.Go
+ }
+ default:
+ if r.Name.Kind == "func" {
+ error_(r.Pos(), "must call C.%s", fixGo(r.Name.Go))
+ }
+ }
+ return expr
+}
+
+// gofmtPos returns the gofmt-formatted string for an AST node,
+// with a comment setting the position before the node.
+func gofmtPos(n ast.Expr, pos token.Pos) string {
+ s := gofmtLine(n)
+ p := fset.Position(pos)
+ if p.Column == 0 {
+ return s
+ }
+ return fmt.Sprintf("/*line :%d:%d*/%s", p.Line, p.Column, s)
+}
+
// gccBaseCmd returns the start of the compiler command line.
// It uses $CC if set, or else $GCC, or else the compiler recorded
// during the initial build as defaultCC.
@@ -1400,6 +1627,9 @@ func (p *Package) gccCmd() []string {
c = append(c, p.GccOptions...)
c = append(c, p.gccMachine()...)
+ if goos == "aix" {
+ c = append(c, "-maix64")
+ }
c = append(c, "-") //read input from standard input
return c
}
@@ -1754,10 +1984,8 @@ func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int6
}
buildStrings()
-
return d, ints, floats, strs
}
-
fatalf("cannot parse gcc output %s as ELF, Mach-O, PE, XCOFF object", gccTmp())
panic("not reached")
}
@@ -1788,6 +2016,11 @@ func (p *Package) gccErrors(stdin []byte) string {
}
}
+ // Force -O0 optimization but keep the trailing "-" at the end.
+ nargs = append(nargs, "-O0")
+ nl := len(nargs)
+ nargs[nl-2], nargs[nl-1] = nargs[nl-1], nargs[nl-2]
+
if *debugGcc {
fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(nargs, " "))
os.Stderr.Write(stdin)
@@ -1829,10 +2062,10 @@ func runGcc(stdin []byte, args []string) (string, string) {
// with equivalent memory layout.
type typeConv struct {
// Cache of already-translated or in-progress types.
- m map[dwarf.Type]*Type
+ m map[string]*Type
// Map from types to incomplete pointers to those types.
- ptrs map[dwarf.Type][]*Type
+ ptrs map[string][]*Type
// Keys of ptrs in insertion order (deterministic worklist)
// ptrKeys contains exactly the keys in ptrs.
ptrKeys []dwarf.Type
@@ -1867,8 +2100,8 @@ var unionWithPointer = make(map[ast.Expr]bool)
func (c *typeConv) Init(ptrSize, intSize int64) {
c.ptrSize = ptrSize
c.intSize = intSize
- c.m = make(map[dwarf.Type]*Type)
- c.ptrs = make(map[dwarf.Type][]*Type)
+ c.m = make(map[string]*Type)
+ c.ptrs = make(map[string][]*Type)
c.getTypeIDs = make(map[string]bool)
c.bool = c.Ident("bool")
c.byte = c.Ident("byte")
@@ -1976,11 +2209,12 @@ func (c *typeConv) FinishType(pos token.Pos) {
// Keep looping until they're all done.
for len(c.ptrKeys) > 0 {
dtype := c.ptrKeys[0]
+ dtypeKey := dtype.String()
c.ptrKeys = c.ptrKeys[1:]
- ptrs := c.ptrs[dtype]
- delete(c.ptrs, dtype)
+ ptrs := c.ptrs[dtypeKey]
+ delete(c.ptrs, dtypeKey)
- // Note Type might invalidate c.ptrs[dtype].
+ // Note Type might invalidate c.ptrs[dtypeKey].
t := c.Type(dtype, pos)
for _, ptr := range ptrs {
ptr.Go.(*ast.StarExpr).X = t.Go
@@ -1992,18 +2226,29 @@ func (c *typeConv) FinishType(pos token.Pos) {
// Type returns a *Type with the same memory layout as
// dtype when used as the type of a variable or a struct field.
func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
- if t, ok := c.m[dtype]; ok {
- if t.Go == nil {
- fatalf("%s: type conversion loop at %s", lineno(pos), dtype)
+ // Always recompute bad pointer typedefs, as the set of such
+ // typedefs changes as we see more types.
+ checkCache := true
+ if dtt, ok := dtype.(*dwarf.TypedefType); ok && c.badPointerTypedef(dtt) {
+ checkCache = false
+ }
+
+ key := dtype.String()
+
+ if checkCache {
+ if t, ok := c.m[key]; ok {
+ if t.Go == nil {
+ fatalf("%s: type conversion loop at %s", lineno(pos), dtype)
+ }
+ return t
}
- return t
}
t := new(Type)
t.Size = dtype.Size() // note: wrong for array of pointers, corrected below
t.Align = -1
t.C = &TypeRepr{Repr: dtype.Common().Name}
- c.m[dtype] = t
+ c.m[key] = t
switch dt := dtype.(type) {
default:
@@ -2166,10 +2411,11 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
// Placeholder initialization; completed in FinishType.
t.Go = &ast.StarExpr{}
t.C.Set("<incomplete>*")
- if _, ok := c.ptrs[dt.Type]; !ok {
+ key := dt.Type.String()
+ if _, ok := c.ptrs[key]; !ok {
c.ptrKeys = append(c.ptrKeys, dt.Type)
}
- c.ptrs[dt.Type] = append(c.ptrs[dt.Type], t)
+ c.ptrs[key] = append(c.ptrs[key], t)
case *dwarf.QualType:
t1 := c.Type(dt.Type, pos)
@@ -2557,11 +2803,6 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
anon := 0
for _, f := range dt.Field {
- if f.ByteOffset > off {
- fld, sizes = c.pad(fld, sizes, f.ByteOffset-off)
- off = f.ByteOffset
- }
-
name := f.Name
ft := f.Type
@@ -2610,6 +2851,19 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
// structs are in system headers that cannot be corrected.
continue
}
+
+ // Round off up to talign, assumed to be a power of 2.
+ off = (off + talign - 1) &^ (talign - 1)
+
+ if f.ByteOffset > off {
+ fld, sizes = c.pad(fld, sizes, f.ByteOffset-off)
+ off = f.ByteOffset
+ }
+ if f.ByteOffset < off {
+ // Drop a packed field that we can't represent.
+ continue
+ }
+
n := len(fld)
fld = fld[0 : n+1]
if name == "" {
@@ -2659,7 +2913,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
return
}
-// dwarfHasPointer returns whether the DWARF type dt contains a pointer.
+// dwarfHasPointer reports whether the DWARF type dt contains a pointer.
func (c *typeConv) dwarfHasPointer(dt dwarf.Type, pos token.Pos) bool {
switch dt := dt.(type) {
default:
@@ -2776,6 +3030,9 @@ func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
if c.badJNI(dt) {
return true
}
+ if c.badEGLDisplay(dt) {
+ return true
+ }
return false
}
@@ -2912,6 +3169,19 @@ func (c *typeConv) badJNI(dt *dwarf.TypedefType) bool {
return false
}
+func (c *typeConv) badEGLDisplay(dt *dwarf.TypedefType) bool {
+ if dt.Name != "EGLDisplay" {
+ return false
+ }
+ // Check that the typedef is "typedef void *EGLDisplay".
+ if ptr, ok := dt.Type.(*dwarf.PtrType); ok {
+ if _, ok := ptr.Type.(*dwarf.VoidType); ok {
+ return true
+ }
+ }
+ return false
+}
+
// jniTypes maps from JNI types that we want to be uintptrs, to the underlying type to which
// they are mapped. The base "jobject" maps to the empty string.
var jniTypes = map[string]string{
diff --git a/libgo/go/cmd/cgo/godefs.go b/libgo/go/cmd/cgo/godefs.go
index 6720945cddd..9c763a22fb0 100644
--- a/libgo/go/cmd/cgo/godefs.go
+++ b/libgo/go/cmd/cgo/godefs.go
@@ -126,3 +126,9 @@ func gofmt(n interface{}) string {
}
return gofmtBuf.String()
}
+
+// gofmtLine returns the gofmt-formatted string for an AST node,
+// ensuring that it is on a single line.
+func gofmtLine(n interface{}) string {
+ return strings.Replace(gofmt(n), "\n", ";", -1)
+}
diff --git a/libgo/go/cmd/cgo/main.go b/libgo/go/cmd/cgo/main.go
index 8e7567b5b0e..4a5c0ca2bab 100644
--- a/libgo/go/cmd/cgo/main.go
+++ b/libgo/go/cmd/cgo/main.go
@@ -47,7 +47,14 @@ type Package struct {
GccFiles []string // list of gcc output files
Preamble string // collected preamble for _cgo_export.h
typedefs map[string]bool // type names that appear in the types of the objects we're interested in
- typedefList []string
+ typedefList []typedefInfo
+}
+
+// A typedefInfo is an element on Package.typedefList: a typedef name
+// and the position where it was required.
+type typedefInfo struct {
+ typedef string
+ pos token.Pos
}
// A File collects information about a single Go input file.
@@ -64,6 +71,9 @@ type File struct {
Edit *edit.Buffer
}
+// Untyped constants in the current package.
+var consts = make(map[string]bool)
+
func (f *File) offset(p token.Pos) int {
return fset.Position(p).Offset
}
@@ -81,6 +91,7 @@ func nameKeys(m map[string]*Name) []string {
type Call struct {
Call *ast.CallExpr
Deferred bool
+ Done bool
}
// A Ref refers to an expression of the form C.xxx in the AST.
@@ -88,19 +99,22 @@ type Ref struct {
Name *Name
Expr *ast.Expr
Context astContext
+ Done bool
}
func (r *Ref) Pos() token.Pos {
return (*r.Expr).Pos()
}
+var nameKinds = []string{"iconst", "fconst", "sconst", "type", "var", "fpvar", "func", "macro", "not-type"}
+
// A Name collects information about C.xxx.
type Name struct {
Go string // name used in Go referring to package C
Mangle string // name used in generated Go
C string // name used in C
Define string // #define expansion
- Kind string // "iconst", "fconst", "sconst", "type", "var", "fpvar", "func", "macro", "not-type"
+ Kind string // one of the nameKinds
Type *Type // the type of xxx
FuncType *FuncType
AddError bool
diff --git a/libgo/go/cmd/cgo/out.go b/libgo/go/cmd/cgo/out.go
index 50e57157793..f44da9c8b12 100644
--- a/libgo/go/cmd/cgo/out.go
+++ b/libgo/go/cmd/cgo/out.go
@@ -9,11 +9,11 @@ import (
"debug/elf"
"debug/macho"
"debug/pe"
- "debug/xcoff"
"fmt"
"go/ast"
"go/printer"
"go/token"
+ "internal/xcoff"
"io"
"io/ioutil"
"os"
@@ -251,7 +251,22 @@ func (p *Package) writeDefs() {
init := gccgoInit.String()
if init != "" {
- fmt.Fprintln(fc, "static void init(void) __attribute__ ((constructor));")
+ // The init function does nothing but simple
+ // assignments, so it won't use much stack space, so
+ // it's OK to not split the stack. Splitting the stack
+ // can run into a bug in clang (as of 2018-11-09):
+ // this is a leaf function, and when clang sees a leaf
+ // function it won't emit the split stack prologue for
+ // the function. However, if this function refers to a
+ // non-split-stack function, which will happen if the
+ // cgo code refers to a C function not compiled with
+ // -fsplit-stack, then the linker will think that it
+ // needs to adjust the split stack prologue, but there
+ // won't be one. Marking the function explicitly
+ // no_split_stack works around this problem by telling
+ // the linker that it's OK if there is no split stack
+ // prologue.
+ fmt.Fprintln(fc, "static void init(void) __attribute__ ((constructor, no_split_stack));")
fmt.Fprintln(fc, "static void init(void) {")
fmt.Fprint(fc, init)
fmt.Fprintln(fc, "}")
@@ -1193,7 +1208,7 @@ func (p *Package) writeExportHeader(fgcch io.Writer) {
fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
}
-// gccgoUsesNewMangling returns whether gccgo uses the new collision-free
+// gccgoUsesNewMangling reports whether gccgo uses the new collision-free
// packagepath mangling scheme (see determineGccgoManglingScheme for more
// info).
func gccgoUsesNewMangling() bool {
@@ -1545,6 +1560,7 @@ const builtinProlog = `
/* Define intgo when compiling with GCC. */
typedef ptrdiff_t intgo;
+#define GO_CGO_GOSTRING_TYPEDEF
typedef struct { const char *p; intgo n; } _GoString_;
typedef struct { char *p; intgo n; intgo c; } _GoBytes_;
_GoString_ GoString(char *p);
@@ -1555,7 +1571,7 @@ void *CBytes(_GoBytes_);
void *_CMalloc(size_t);
__attribute__ ((unused))
-static size_t _GoStringLen(_GoString_ s) { return s.n; }
+static size_t _GoStringLen(_GoString_ s) { return (size_t)s.n; }
__attribute__ ((unused))
static const char *_GoStringPtr(_GoString_ s) { return s.p; }
@@ -1796,15 +1812,20 @@ void localCgoCheckResult(Eface val) {
// because _cgo_export.h defines GoString as a struct while builtinProlog
// defines it as a function. We don't change this to avoid unnecessarily
// breaking existing code.
+// The test of GO_CGO_GOSTRING_TYPEDEF avoids a duplicate definition
+// error if a Go file with a cgo comment #include's the export header
+// generated by a different package.
const builtinExportProlog = `
-#line 1 "cgo-builtin-prolog"
+#line 1 "cgo-builtin-export-prolog"
#include <stddef.h> /* for ptrdiff_t below */
#ifndef GO_CGO_EXPORT_PROLOGUE_H
#define GO_CGO_EXPORT_PROLOGUE_H
+#ifndef GO_CGO_GOSTRING_TYPEDEF
typedef struct { const char *p; ptrdiff_t n; } _GoString_;
+#endif
#endif
`
@@ -1813,6 +1834,19 @@ func (p *Package) gccExportHeaderProlog() string {
return strings.Replace(gccExportHeaderProlog, "GOINTBITS", fmt.Sprint(8*p.IntSize), -1)
}
+// gccExportHeaderProlog is written to the exported header, after the
+// import "C" comment preamble but before the generated declarations
+// of exported functions. This permits the generated declarations to
+// use the type names that appear in goTypes, above.
+//
+// The test of GO_CGO_GOSTRING_TYPEDEF avoids a duplicate definition
+// error if a Go file with a cgo comment #include's the export header
+// generated by a different package. Unfortunately GoString means two
+// different things: in this prolog it means a C name for the Go type,
+// while in the prolog written into the start of the C code generated
+// from a cgo-using Go file it means the C.GoString function. There is
+// no way to resolve this conflict, but it also doesn't make much
+// difference, as Go code never wants to refer to the latter meaning.
const gccExportHeaderProlog = `
/* Start of boilerplate cgo prologue. */
#line 1 "cgo-gcc-export-header-prolog"
@@ -1842,7 +1876,9 @@ typedef double _Complex GoComplex128;
*/
typedef char _check_for_GOINTBITS_bit_pointer_matching_GoInt[sizeof(void*)==GOINTBITS/8 ? 1:-1];
+#ifndef GO_CGO_GOSTRING_TYPEDEF
typedef _GoString_ GoString;
+#endif
typedef void *GoMap;
typedef void *GoChan;
typedef struct { void *t; void *v; } GoInterface;
diff --git a/libgo/go/cmd/go/alldocs.go b/libgo/go/cmd/go/alldocs.go
index 1060e779c1b..9d9304a3b64 100644
--- a/libgo/go/cmd/go/alldocs.go
+++ b/libgo/go/cmd/go/alldocs.go
@@ -144,7 +144,7 @@
// link against shared libraries previously created with
// -buildmode=shared.
// -mod mode
-// module download mode to use: readonly, release, or vendor.
+// module download mode to use: readonly or vendor.
// See 'go help modules' for more.
// -pkgdir dir
// install and load all packages from dir instead of the usual locations.
@@ -342,12 +342,21 @@
// cd go/src/encoding/json; go doc decode
//
// Flags:
+// -all
+// Show all the documentation for the package.
// -c
// Respect case when matching symbols.
// -cmd
// Treat a command (package main) like a regular package.
// Otherwise package main's exported symbols are hidden
// when showing the package's top-level documentation.
+// -src
+// Show the full source code for the symbol. This will
+// display the full Go source of its declaration and
+// definition, such as a function definition (including
+// the body), type declaration or enclosing const
+// block. The output may therefore include unexported
+// details.
// -u
// Show documentation for unexported as well as exported
// symbols, methods, and fields.
@@ -889,7 +898,7 @@
//
// Usage:
//
-// go mod download [-dir] [-json] [modules]
+// go mod download [-json] [modules]
//
// Download downloads the named modules, which can be module patterns selecting
// dependencies of the main module or module queries of the form path@version.
@@ -963,6 +972,8 @@
// and -dropreplace editing flags may be repeated, and the changes
// are applied in the order given.
//
+// The -go=version flag sets the expected Go language version.
+//
// The -print flag prints the final go.mod in its text format instead of
// writing it back to go.mod.
//
@@ -975,7 +986,8 @@
// }
//
// type GoMod struct {
-// Module Module
+// Module Module
+// Go string
// Require []Require
// Exclude []Module
// Replace []Replace
@@ -1287,16 +1299,25 @@
//
// Usage:
//
-// go vet [-n] [-x] [build flags] [vet flags] [packages]
+// go vet [-n] [-x] [-vettool prog] [build flags] [vet flags] [packages]
//
// Vet runs the Go vet command on the packages named by the import paths.
//
// For more about vet and its flags, see 'go doc cmd/vet'.
// For more about specifying packages, see 'go help packages'.
+// For a list of checkers and their flags, see 'go tool vet help'.
+// For details of a specific checker such as 'printf', see 'go tool vet help printf'.
//
// The -n flag prints commands that would be executed.
// The -x flag prints commands as they are executed.
//
+// The -vettool=prog flag selects a different analysis tool with alternative
+// or additional checks.
+// For example, the 'shadow' analyzer can be built and run using these commands:
+//
+// go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow
+// go vet -vettool=$(which shadow)
+//
// The build flags supported by go vet are those that control package resolution
// and execution, such as -n, -x, -v, -tags, and -toolexec.
// For more about these flags, see 'go help build'.
@@ -1451,9 +1472,7 @@
//
// Each entry in the GOFLAGS list must be a standalone flag.
// Because the entries are space-separated, flag values must
-// not contain spaces. In some cases, you can provide multiple flag
-// values instead: for example, to set '-ldflags=-s -w'
-// you can use 'GOFLAGS=-ldflags=-s -ldflags=-w'.
+// not contain spaces.
//
// Environment variables for use with cgo:
//
@@ -1488,6 +1507,10 @@
// The command to use to compile C++ code.
// PKG_CONFIG
// Path to pkg-config tool.
+// AR
+// The command to use to manipulate library archives when
+// building with the gccgo compiler.
+// The default is 'ar'.
//
// Architecture-specific environment variables:
//
@@ -1595,17 +1618,20 @@
// verb followed by arguments. For example:
//
// module my/thing
+// go 1.12
// require other/thing v1.0.2
-// require new/thing v2.3.4
+// require new/thing/v2 v2.3.4
// exclude old/thing v1.2.3
// replace bad/thing v1.4.5 => good/thing v1.4.5
//
-// The verbs are module, to define the module path; require, to require
-// a particular module at a given version or later; exclude, to exclude
-// a particular module version from use; and replace, to replace a module
-// version with a different module version. Exclude and replace apply only
-// in the main module's go.mod and are ignored in dependencies.
-// See https://research.swtch.com/vgo-mvs for details.
+// The verbs are
+// module, to define the module path;
+// go, to set the expected language version;
+// require, to require a particular module at a given version or later;
+// exclude, to exclude a particular module version from use; and
+// replace, to replace a module version with a different module version.
+// Exclude and replace apply only in the main module's go.mod and are ignored
+// in dependencies. See https://research.swtch.com/vgo-mvs for details.
//
// The leading verb can be factored out of adjacent lines to create a block,
// like in Go imports:
@@ -2028,7 +2054,7 @@
// (See 'go help gopath-get' and 'go help gopath'.)
//
// When using modules, downloaded packages are stored in the module cache.
-// (See 'go help modules-get' and 'go help goproxy'.)
+// (See 'go help module-get' and 'go help goproxy'.)
//
// When using modules, an additional variant of the go-import meta tag is
// recognized and is preferred over those listing version control systems.
@@ -2490,7 +2516,7 @@
// In general, adding a new dependency may require upgrading
// existing dependencies to keep a working build, and 'go get' does
// this automatically. Similarly, downgrading one dependency may
-// require downgrading other dependenceis, and 'go get' does
+// require downgrading other dependencies, and 'go get' does
// this automatically as well.
//
// The -m flag instructs get to stop here, after resolving, upgrading,
@@ -2652,6 +2678,8 @@
// Run enough iterations of each benchmark to take t, specified
// as a time.Duration (for example, -benchtime 1h30s).
// The default is 1 second (1s).
+// The special syntax Nx means to run the benchmark N times
+// (for example, -benchtime 100x).
//
// -count n
// Run each test and benchmark n times (default 1).
diff --git a/libgo/go/cmd/go/go_test.go b/libgo/go/cmd/go/go_test.go
index e88338815c3..63549cfded6 100644
--- a/libgo/go/cmd/go/go_test.go
+++ b/libgo/go/cmd/go/go_test.go
@@ -6,6 +6,8 @@ package main_test
import (
"bytes"
+ "cmd/internal/sys"
+ "context"
"debug/elf"
"debug/macho"
"flag"
@@ -107,6 +109,12 @@ var testGo string
var testTmpDir string
var testBin string
+// testCtx is canceled when the test binary is about to time out.
+//
+// If https://golang.org/issue/28135 is accepted, uses of this variable in test
+// functions should be replaced by t.Context().
+var testCtx = context.Background()
+
// The TestMain function creates a go command for testing purposes and
// deletes it after the tests have been run.
func TestMain(m *testing.M) {
@@ -119,6 +127,20 @@ func TestMain(m *testing.M) {
os.Unsetenv("GOROOT_FINAL")
flag.Parse()
+
+ timeoutFlag := flag.Lookup("test.timeout")
+ if timeoutFlag != nil {
+ // TODO(golang.org/issue/28147): The go command does not pass the
+ // test.timeout flag unless either -timeout or -test.timeout is explicitly
+ // set on the command line.
+ if d := timeoutFlag.Value.(flag.Getter).Get().(time.Duration); d != 0 {
+ aBitShorter := d * 95 / 100
+ var cancel context.CancelFunc
+ testCtx, cancel = context.WithTimeout(testCtx, aBitShorter)
+ defer cancel()
+ }
+ }
+
if *proxyAddr != "" {
StartProxy()
select {}
@@ -209,15 +231,13 @@ func TestMain(m *testing.M) {
}
testGOCACHE = strings.TrimSpace(string(out))
- // As of Sept 2017, MSan is only supported on linux/amd64.
- // https://github.com/google/sanitizers/wiki/MemorySanitizer#getting-memorysanitizer
- canMSan = canCgo && runtime.GOOS == "linux" && runtime.GOARCH == "amd64"
-
- switch runtime.GOOS {
- case "linux", "darwin", "freebsd", "windows":
- // The race detector doesn't work on Alpine Linux:
- // golang.org/issue/14481
- canRace = canCgo && runtime.GOARCH == "amd64" && !isAlpineLinux() && runtime.Compiler != "gccgo"
+ canMSan = canCgo && sys.MSanSupported(runtime.GOOS, runtime.GOARCH)
+ canRace = canCgo && sys.RaceDetectorSupported(runtime.GOOS, runtime.GOARCH)
+ // The race detector doesn't work on Alpine Linux:
+ // golang.org/issue/14481
+ // gccgo does not support the race detector.
+ if isAlpineLinux() || runtime.Compiler == "gccgo" {
+ canRace = false
}
}
// Don't let these environment variables confuse the test.
@@ -1075,6 +1095,8 @@ func testMove(t *testing.T, vcs, url, base, config string) {
defer tg.cleanup()
tg.parallel()
tg.tempDir("src")
+ tg.must(os.Mkdir(tg.path(".hg"), 0700))
+ tg.must(ioutil.WriteFile(filepath.Join(tg.path(".hg"), "hgrc"), nil, 0600))
tg.setenv("GOPATH", tg.path("."))
tg.run("get", "-d", url)
tg.run("get", "-d", "-u", url)
@@ -1089,7 +1111,7 @@ func testMove(t *testing.T, vcs, url, base, config string) {
path := tg.path(filepath.Join("src", config))
data, err := ioutil.ReadFile(path)
tg.must(err)
- data = bytes.Replace(data, []byte(base), []byte(base+"XXX"), -1)
+ data = bytes.ReplaceAll(data, []byte(base), []byte(base+"XXX"))
tg.must(ioutil.WriteFile(path, data, 0644))
}
if vcs == "git" {
@@ -1185,22 +1207,6 @@ func TestImportCycle(t *testing.T) {
tg.run("list", "-e", "-json", "selfimport")
}
-func TestListImportMap(t *testing.T) {
- skipIfGccgo(t, "gccgo does not have standard packages")
- tg := testgo(t)
- defer tg.cleanup()
- tg.parallel()
- tg.run("list", "-f", "{{.ImportPath}}: {{.ImportMap}}", "net", "fmt")
- tg.grepStdout(`^net: map\[(.* )?golang_org/x/net/dns/dnsmessage:vendor/golang_org/x/net/dns/dnsmessage.*\]`, "net/http should have rewritten dnsmessage import")
- tg.grepStdout(`^fmt: map\[\]`, "fmt should have no rewritten imports")
- tg.run("list", "-deps", "-test", "-f", "{{.ImportPath}} MAP: {{.ImportMap}}\n{{.ImportPath}} IMPORT: {{.Imports}}", "fmt")
- tg.grepStdout(`^flag \[fmt\.test\] MAP: map\[fmt:fmt \[fmt\.test\]\]`, "flag [fmt.test] should import fmt [fmt.test] as fmt")
- tg.grepStdout(`^fmt\.test MAP: map\[(.* )?testing:testing \[fmt\.test\]`, "fmt.test should import testing [fmt.test] as testing")
- tg.grepStdout(`^fmt\.test MAP: map\[(.* )?testing:testing \[fmt\.test\]`, "fmt.test should import testing [fmt.test] as testing")
- tg.grepStdoutNot(`^fmt\.test MAP: map\[(.* )?os:`, "fmt.test should not import a modified os")
- tg.grepStdout(`^fmt\.test IMPORT: \[fmt \[fmt\.test\] fmt_test \[fmt\.test\] os testing \[fmt\.test\] testing/internal/testdeps \[fmt\.test\]\]`, "wrong imports for fmt.test")
-}
-
// cmd/go: custom import path checking should not apply to Go packages without import comment.
func TestIssue10952(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
@@ -1421,6 +1427,7 @@ func TestRelativeGOBINFail(t *testing.T) {
tg.tempFile("triv.go", `package main; func main() {}`)
tg.cd(tg.path("."))
tg.setenv("GOBIN", ".")
+ tg.cd(tg.path("."))
tg.runFail("install")
tg.grepStderr("cannot install, GOBIN must be an absolute path", "go install must fail if $GOBIN is a relative path")
}
@@ -1440,8 +1447,38 @@ func TestInstallIntoGOPATH(t *testing.T) {
func TestBuildOutputToDevNull(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ fi1, err1 := os.Lstat(os.DevNull)
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.run("build", "-o", os.DevNull, "go-cmd-test")
+ fi2, err2 := os.Lstat(os.DevNull)
+ if err1 == nil {
+ if err2 != nil {
+ t.Errorf("second stat of /dev/null failed: %v", err2)
+ } else if !os.SameFile(fi1, fi2) {
+ t.Errorf("/dev/null changed: now %v was %v", fi1, fi2)
+ }
+ }
+}
+
+// Issue 28549.
+func TestTestOutputToDevNull(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ fi1, err1 := os.Lstat(os.DevNull)
+ tg.makeTempdir()
+ tg.setenv("GOPATH", tg.path("."))
+ tg.tempFile("src/p/p.go", "package p\n")
+ tg.tempFile("src/p/p_test.go", "package p\nimport \"testing\"\nfunc TestX(t *testing.T) {}\n")
+ tg.run("test", "-o", os.DevNull, "-c", "p")
+ tg.mustNotExist("p.test")
+ fi2, err2 := os.Lstat(os.DevNull)
+ if err1 == nil {
+ if err2 != nil {
+ t.Errorf("second stat of /dev/null failed: %v", err2)
+ } else if !os.SameFile(fi1, fi2) {
+ t.Errorf("/dev/null changed: now %v was %v", fi1, fi2)
+ }
+ }
}
func TestPackageMainTestImportsArchiveNotBinary(t *testing.T) {
@@ -1735,11 +1772,11 @@ func TestGoListDeps(t *testing.T) {
if runtime.Compiler != "gccgo" {
// Check the list is in dependency order.
tg.run("list", "-deps", "math")
- want := "internal/cpu\nunsafe\nmath\n"
+ want := "internal/cpu\nunsafe\nmath/bits\nmath\n"
out := tg.stdout.String()
if !strings.Contains(out, "internal/cpu") {
// Some systems don't use internal/cpu.
- want = "unsafe\nmath\n"
+ want = "unsafe\nmath/bits\nmath\n"
}
if tg.stdout.String() != want {
t.Fatalf("list -deps math: wrong order\nhave %q\nwant %q", tg.stdout.String(), want)
@@ -2359,14 +2396,14 @@ func TestShadowingLogic(t *testing.T) {
// The math in root1 is not "math" because the standard math is.
tg.run("list", "-f", "({{.ImportPath}}) ({{.ConflictDir}})", "./testdata/shadow/root1/src/math")
- pwdForwardSlash := strings.Replace(pwd, string(os.PathSeparator), "/", -1)
+ pwdForwardSlash := strings.ReplaceAll(pwd, string(os.PathSeparator), "/")
if !strings.HasPrefix(pwdForwardSlash, "/") {
pwdForwardSlash = "/" + pwdForwardSlash
}
// The output will have makeImportValid applies, but we only
// bother to deal with characters we might reasonably see.
for _, r := range " :" {
- pwdForwardSlash = strings.Replace(pwdForwardSlash, string(r), "_", -1)
+ pwdForwardSlash = strings.ReplaceAll(pwdForwardSlash, string(r), "_")
}
want := "(_" + pwdForwardSlash + "/testdata/shadow/root1/src/math) (" + filepath.Join(runtime.GOROOT(), "src", "math") + ")"
if strings.TrimSpace(tg.getStdout()) != want {
@@ -2556,7 +2593,7 @@ func TestCoverageErrorLine(t *testing.T) {
// It's OK that stderr2 drops the character position in the error,
// because of the //line directive (see golang.org/issue/22662).
- stderr = strings.Replace(stderr, "p.go:4:2:", "p.go:4:", -1)
+ stderr = strings.ReplaceAll(stderr, "p.go:4:2:", "p.go:4:")
if stderr != stderr2 {
t.Logf("test -cover changed error messages:\nbefore:\n%s\n\nafter:\n%s", stderr, stderr2)
t.Skip("golang.org/issue/22660")
@@ -4027,8 +4064,6 @@ func TestCgoConsistentResults(t *testing.T) {
t.Skip("skipping because cgo not enabled")
}
switch runtime.GOOS {
- case "freebsd":
- testenv.SkipFlaky(t, 15405)
case "solaris":
testenv.SkipFlaky(t, 13247)
}
@@ -4977,7 +5012,8 @@ func TestExecBuildX(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
- tg.setenv("GOCACHE", "off")
+ tg.tempDir("cache")
+ tg.setenv("GOCACHE", tg.path("cache"))
tg.tempFile("main.go", `package main; import "C"; func main() { print("hello") }`)
src := tg.path("main.go")
@@ -5508,30 +5544,6 @@ func TestTestCacheInputs(t *testing.T) {
}
}
-func TestNoCache(t *testing.T) {
- switch runtime.GOOS {
- case "windows":
- t.Skipf("no unwritable directories on %s", runtime.GOOS)
- }
- if os.Getuid() == 0 {
- t.Skip("skipping test because running as root")
- }
-
- tg := testgo(t)
- defer tg.cleanup()
- tg.parallel()
- tg.tempFile("triv.go", `package main; func main() {}`)
- tg.must(os.MkdirAll(tg.path("unwritable"), 0555))
- home := "HOME"
- if runtime.GOOS == "plan9" {
- home = "home"
- }
- tg.setenv(home, tg.path(filepath.Join("unwritable", "home")))
- tg.unsetenv("GOCACHE")
- tg.run("build", "-o", tg.path("triv"), tg.path("triv.go"))
- tg.grepStderr("disabling cache", "did not disable cache")
-}
-
func TestTestVet(t *testing.T) {
tooSlow(t)
tg := testgo(t)
@@ -5681,17 +5693,6 @@ func TestFmtLoadErrors(t *testing.T) {
tg.run("fmt", "-n", "exclude")
}
-func TestRelativePkgdir(t *testing.T) {
- tooSlow(t)
- tg := testgo(t)
- defer tg.cleanup()
- tg.makeTempdir()
- tg.setenv("GOCACHE", "off")
- tg.cd(tg.tempdir)
-
- tg.run("build", "-i", "-pkgdir=.", "runtime")
-}
-
func TestGoTestMinusN(t *testing.T) {
// Intent here is to verify that 'go test -n' works without crashing.
// This reuses flag_test.go, but really any test would do.
@@ -6073,28 +6074,6 @@ func TestDontReportRemoveOfEmptyDir(t *testing.T) {
}
}
-// Issue 23264.
-func TestNoRelativeTmpdir(t *testing.T) {
- tg := testgo(t)
- defer tg.cleanup()
-
- tg.tempFile("src/a/a.go", `package a`)
- tg.cd(tg.path("."))
- tg.must(os.Mkdir("tmp", 0777))
-
- tg.setenv("GOCACHE", "off")
- tg.setenv("GOPATH", tg.path("."))
- tg.setenv("GOTMPDIR", "tmp")
- tg.run("build", "-work", "a")
- tg.grepStderr("WORK=[^t]", "work should be absolute path")
-
- tg.unsetenv("GOTMPDIR")
- tg.setenv("TMP", "tmp") // windows
- tg.setenv("TMPDIR", "tmp") // unix
- tg.run("build", "-work", "a")
- tg.grepStderr("WORK=[^t]", "work should be absolute path")
-}
-
// Issue 24704.
func TestLinkerTmpDirIsDeleted(t *testing.T) {
skipIfGccgo(t, "gccgo does not use cmd/link")
@@ -6172,7 +6151,7 @@ func TestCDAndGOPATHAreDifferent(t *testing.T) {
testCDAndGOPATHAreDifferent(tg, cd, gopath)
if runtime.GOOS == "windows" {
- testCDAndGOPATHAreDifferent(tg, cd, strings.Replace(gopath, `\`, `/`, -1))
+ testCDAndGOPATHAreDifferent(tg, cd, strings.ReplaceAll(gopath, `\`, `/`))
testCDAndGOPATHAreDifferent(tg, cd, strings.ToUpper(gopath))
testCDAndGOPATHAreDifferent(tg, cd, strings.ToLower(gopath))
}
diff --git a/libgo/go/cmd/go/help_test.go b/libgo/go/cmd/go/help_test.go
new file mode 100644
index 00000000000..ec6a9d11cbe
--- /dev/null
+++ b/libgo/go/cmd/go/help_test.go
@@ -0,0 +1,28 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !nacl
+
+package main_test
+
+import (
+ "bytes"
+ "io/ioutil"
+ "testing"
+
+ "cmd/go/internal/help"
+)
+
+func TestDocsUpToDate(t *testing.T) {
+ buf := new(bytes.Buffer)
+ // Match the command in mkalldocs.sh that generates alldocs.go.
+ help.Help(buf, []string{"documentation"})
+ data, err := ioutil.ReadFile("alldocs.go")
+ if err != nil {
+ t.Fatalf("error reading alldocs.go: %v", err)
+ }
+ if !bytes.Equal(data, buf.Bytes()) {
+ t.Errorf("alldocs.go is not up to date; run mkalldocs.sh to regenerate it")
+ }
+}
diff --git a/libgo/go/cmd/go/internal/cache/cache.go b/libgo/go/cmd/go/internal/cache/cache.go
index 0cf01550ff9..ab84cf6302c 100644
--- a/libgo/go/cmd/go/internal/cache/cache.go
+++ b/libgo/go/cmd/go/internal/cache/cache.go
@@ -18,6 +18,8 @@ import (
"strconv"
"strings"
"time"
+
+ "cmd/go/internal/renameio"
)
// An ActionID is a cache action key, the hash of a complete description of a
@@ -283,7 +285,9 @@ func (c *Cache) Trim() {
c.trimSubdir(subdir, cutoff)
}
- ioutil.WriteFile(filepath.Join(c.dir, "trim.txt"), []byte(fmt.Sprintf("%d", now.Unix())), 0666)
+ // Ignore errors from here: if we don't write the complete timestamp, the
+ // cache will appear older than it is, and we'll trim it again next time.
+ renameio.WriteFile(filepath.Join(c.dir, "trim.txt"), []byte(fmt.Sprintf("%d", now.Unix())))
}
// trimSubdir trims a single cache subdirectory.
@@ -338,6 +342,8 @@ func (c *Cache) putIndexEntry(id ActionID, out OutputID, size int64, allowVerify
}
file := c.fileName(id, "a")
if err := ioutil.WriteFile(file, entry, 0666); err != nil {
+ // TODO(bcmills): This Remove potentially races with another go command writing to file.
+ // Can we eliminate it?
os.Remove(file)
return err
}
diff --git a/libgo/go/cmd/go/internal/cache/default.go b/libgo/go/cmd/go/internal/cache/default.go
index 02fc1e896f7..f545c147009 100644
--- a/libgo/go/cmd/go/internal/cache/default.go
+++ b/libgo/go/cmd/go/internal/cache/default.go
@@ -9,8 +9,9 @@ import (
"io/ioutil"
"os"
"path/filepath"
- "runtime"
"sync"
+
+ "cmd/go/internal/base"
)
// Default returns the default cache to use, or nil if no cache should be used.
@@ -35,15 +36,15 @@ See golang.org to learn more about Go.
// initDefaultCache does the work of finding the default cache
// the first time Default is called.
func initDefaultCache() {
- dir, showWarnings := defaultDir()
- if dir == "off" {
- return
+ dir := DefaultDir()
+ if dir == "off" || dir == "" {
+ if defaultDirErr != nil {
+ base.Fatalf("build cache is required, but could not be located: %v", defaultDirErr)
+ }
+ base.Fatalf("build cache is disabled by GOCACHE=off, but required as of Go 1.12")
}
if err := os.MkdirAll(dir, 0777); err != nil {
- if showWarnings {
- fmt.Fprintf(os.Stderr, "go: disabling cache (%s) due to initialization failure: %s\n", dir, err)
- }
- return
+ base.Fatalf("failed to initialize build cache at %s: %s\n", dir, err)
}
if _, err := os.Stat(filepath.Join(dir, "README")); err != nil {
// Best effort.
@@ -52,78 +53,40 @@ func initDefaultCache() {
c, err := Open(dir)
if err != nil {
- if showWarnings {
- fmt.Fprintf(os.Stderr, "go: disabling cache (%s) due to initialization failure: %s\n", dir, err)
- }
- return
+ base.Fatalf("failed to initialize build cache at %s: %s\n", dir, err)
}
defaultCache = c
}
+var (
+ defaultDirOnce sync.Once
+ defaultDir string
+ defaultDirErr error
+)
+
// DefaultDir returns the effective GOCACHE setting.
// It returns "off" if the cache is disabled.
func DefaultDir() string {
- dir, _ := defaultDir()
- return dir
-}
+ // Save the result of the first call to DefaultDir for later use in
+ // initDefaultCache. cmd/go/main.go explicitly sets GOCACHE so that
+ // subprocesses will inherit it, but that means initDefaultCache can't
+ // otherwise distinguish between an explicit "off" and a UserCacheDir error.
-// defaultDir returns the effective GOCACHE setting.
-// It returns "off" if the cache is disabled.
-// The second return value reports whether warnings should
-// be shown if the cache fails to initialize.
-func defaultDir() (string, bool) {
- dir := os.Getenv("GOCACHE")
- if dir != "" {
- return dir, true
- }
-
- // Compute default location.
- // TODO(rsc): This code belongs somewhere else,
- // like maybe ioutil.CacheDir or os.CacheDir.
- showWarnings := true
- 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", true
+ defaultDirOnce.Do(func() {
+ defaultDir = os.Getenv("GOCACHE")
+ if defaultDir != "" {
+ return
}
- case "darwin":
- dir = os.Getenv("HOME")
- if dir == "" {
- return "off", true
+ // Compute default location.
+ dir, err := os.UserCacheDir()
+ if err != nil {
+ defaultDir = "off"
+ defaultDirErr = fmt.Errorf("GOCACHE is not defined and %v", err)
+ return
}
- dir += "/Library/Caches"
+ defaultDir = filepath.Join(dir, "go-build")
+ })
- case "plan9":
- dir = os.Getenv("home")
- if dir == "" {
- return "off", true
- }
- // Plan 9 has no established per-user cache directory,
- // but $home/lib/xyz is the usual equivalent of $HOME/.xyz on Unix.
- dir += "/lib/cache"
-
- default: // Unix
- // https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
- dir = os.Getenv("XDG_CACHE_HOME")
- if dir == "" {
- dir = os.Getenv("HOME")
- if dir == "" {
- return "off", true
- }
- if dir == "/" {
- // probably docker run with -u flag
- // https://golang.org/issue/26280
- showWarnings = false
- }
- dir += "/.cache"
- }
- }
- return filepath.Join(dir, "go-build"), showWarnings
+ return defaultDir
}
diff --git a/libgo/go/cmd/go/internal/cache/default_unix_test.go b/libgo/go/cmd/go/internal/cache/default_unix_test.go
deleted file mode 100644
index a207497a42c..00000000000
--- a/libgo/go/cmd/go/internal/cache/default_unix_test.go
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2018 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !windows,!darwin,!plan9
-
-package cache
-
-import (
- "os"
- "strings"
- "testing"
-)
-
-func TestDefaultDir(t *testing.T) {
- goCacheDir := "/tmp/test-go-cache"
- xdgCacheDir := "/tmp/test-xdg-cache"
- homeDir := "/tmp/test-home"
-
- // undo env changes when finished
- defer func(GOCACHE, XDG_CACHE_HOME, HOME string) {
- os.Setenv("GOCACHE", GOCACHE)
- os.Setenv("XDG_CACHE_HOME", XDG_CACHE_HOME)
- os.Setenv("HOME", HOME)
- }(os.Getenv("GOCACHE"), os.Getenv("XDG_CACHE_HOME"), os.Getenv("HOME"))
-
- os.Setenv("GOCACHE", goCacheDir)
- os.Setenv("XDG_CACHE_HOME", xdgCacheDir)
- os.Setenv("HOME", homeDir)
-
- dir, showWarnings := defaultDir()
- if dir != goCacheDir {
- t.Errorf("Cache DefaultDir %q should be $GOCACHE %q", dir, goCacheDir)
- }
- if !showWarnings {
- t.Error("Warnings should be shown when $GOCACHE is set")
- }
-
- os.Unsetenv("GOCACHE")
- dir, showWarnings = defaultDir()
- if !strings.HasPrefix(dir, xdgCacheDir+"/") {
- t.Errorf("Cache DefaultDir %q should be under $XDG_CACHE_HOME %q when $GOCACHE is unset", dir, xdgCacheDir)
- }
- if !showWarnings {
- t.Error("Warnings should be shown when $XDG_CACHE_HOME is set")
- }
-
- os.Unsetenv("XDG_CACHE_HOME")
- dir, showWarnings = defaultDir()
- if !strings.HasPrefix(dir, homeDir+"/.cache/") {
- t.Errorf("Cache DefaultDir %q should be under $HOME/.cache %q when $GOCACHE and $XDG_CACHE_HOME are unset", dir, homeDir+"/.cache")
- }
- if !showWarnings {
- t.Error("Warnings should be shown when $HOME is not /")
- }
-
- os.Unsetenv("HOME")
- if dir, _ := defaultDir(); dir != "off" {
- t.Error("Cache not disabled when $GOCACHE, $XDG_CACHE_HOME, and $HOME are unset")
- }
-
- os.Setenv("HOME", "/")
- if _, showWarnings := defaultDir(); showWarnings {
- // https://golang.org/issue/26280
- t.Error("Cache initalization warnings should be squelched when $GOCACHE and $XDG_CACHE_HOME are unset and $HOME is /")
- }
-}
diff --git a/libgo/go/cmd/go/internal/cache/hash.go b/libgo/go/cmd/go/internal/cache/hash.go
index 0e45e7db547..e4bb2a34bb4 100644
--- a/libgo/go/cmd/go/internal/cache/hash.go
+++ b/libgo/go/cmd/go/internal/cache/hash.go
@@ -123,7 +123,7 @@ var hashFileCache struct {
m map[string][HashSize]byte
}
-// HashFile returns the hash of the named file.
+// FileHash returns the hash of the named file.
// It caches repeated lookups for a given file,
// and the cache entry for a file can be initialized
// using SetFileHash.
diff --git a/libgo/go/cmd/go/internal/clean/clean.go b/libgo/go/cmd/go/internal/clean/clean.go
index d023592eedc..32cc80736df 100644
--- a/libgo/go/cmd/go/internal/clean/clean.go
+++ b/libgo/go/cmd/go/internal/clean/clean.go
@@ -10,6 +10,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
+ "strconv"
"strings"
"time"
@@ -17,6 +18,7 @@ import (
"cmd/go/internal/cache"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
+ "cmd/go/internal/lockedfile"
"cmd/go/internal/modfetch"
"cmd/go/internal/modload"
"cmd/go/internal/work"
@@ -103,18 +105,16 @@ func init() {
}
func runClean(cmd *base.Command, args []string) {
- if len(args) == 0 && modload.Failed() {
- // Don't try to clean current directory,
- // which will cause modload to base.Fatalf.
- } else {
+ if len(args) > 0 || !modload.Enabled() || modload.HasModRoot() {
for _, pkg := range load.PackagesAndErrors(args) {
clean(pkg)
}
}
+ var b work.Builder
+ b.Print = fmt.Print
+
if cleanCache {
- var b work.Builder
- b.Print = fmt.Print
dir := cache.DefaultDir()
if dir != "off" {
// Remove the cache subdirectories but not the top cache directory.
@@ -145,7 +145,20 @@ func runClean(cmd *base.Command, args []string) {
// right now are to be ignored.
dir := cache.DefaultDir()
if dir != "off" {
- err := ioutil.WriteFile(filepath.Join(dir, "testexpire.txt"), []byte(fmt.Sprintf("%d\n", time.Now().UnixNano())), 0666)
+ f, err := lockedfile.Edit(filepath.Join(dir, "testexpire.txt"))
+ if err == nil {
+ now := time.Now().UnixNano()
+ buf, _ := ioutil.ReadAll(f)
+ prev, _ := strconv.ParseInt(strings.TrimSpace(string(buf)), 10, 64)
+ if now > prev {
+ if err = f.Truncate(0); err == nil {
+ _, err = fmt.Fprintf(f, "%d\n", now)
+ }
+ }
+ if closeErr := f.Close(); err == nil {
+ err = closeErr
+ }
+ }
if err != nil {
base.Errorf("go clean -testcache: %v", err)
}
@@ -156,24 +169,15 @@ func runClean(cmd *base.Command, args []string) {
if modfetch.PkgMod == "" {
base.Fatalf("go clean -modcache: no module cache")
}
- if err := removeAll(modfetch.PkgMod); err != nil {
- base.Errorf("go clean -modcache: %v", err)
- }
- }
-}
-
-func removeAll(dir string) error {
- // Module cache has 0555 directories; make them writable in order to remove content.
- filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
- if err != nil {
- return nil // ignore errors walking in file system
+ if cfg.BuildN || cfg.BuildX {
+ b.Showcmd("", "rm -rf %s", modfetch.PkgMod)
}
- if info.IsDir() {
- os.Chmod(path, 0777)
+ if !cfg.BuildN {
+ if err := modfetch.RemoveAll(modfetch.PkgMod); err != nil {
+ base.Errorf("go clean -modcache: %v", err)
+ }
}
- return nil
- })
- return os.RemoveAll(dir)
+ }
}
var cleaned = map[*load.Package]bool{}
diff --git a/libgo/go/cmd/go/internal/cmdflag/flag.go b/libgo/go/cmd/go/internal/cmdflag/flag.go
index b2a67e6f74a..7f2c53def8f 100644
--- a/libgo/go/cmd/go/internal/cmdflag/flag.go
+++ b/libgo/go/cmd/go/internal/cmdflag/flag.go
@@ -79,15 +79,15 @@ func AddKnownFlags(cmd string, defns []*Defn) {
// Parse sees if argument i is present in the definitions and if so,
// returns its definition, value, and whether it consumed an extra word.
-// If the flag begins (cmd+".") it is ignored for the purpose of this function.
-func Parse(cmd string, defns []*Defn, args []string, i int) (f *Defn, value string, extra bool) {
+// If the flag begins (cmd.Name()+".") it is ignored for the purpose of this function.
+func Parse(cmd string, usage func(), defns []*Defn, args []string, i int) (f *Defn, value string, extra bool) {
arg := args[i]
if strings.HasPrefix(arg, "--") { // reduce two minuses to one
arg = arg[1:]
}
switch arg {
case "-?", "-h", "-help":
- base.Usage()
+ usage()
}
if arg == "" || arg[0] != '-' {
return
diff --git a/libgo/go/cmd/go/internal/doc/doc.go b/libgo/go/cmd/go/internal/doc/doc.go
index 4e7dca082d7..bad05ff9128 100644
--- a/libgo/go/cmd/go/internal/doc/doc.go
+++ b/libgo/go/cmd/go/internal/doc/doc.go
@@ -106,12 +106,21 @@ Examples:
cd go/src/encoding/json; go doc decode
Flags:
+ -all
+ Show all the documentation for the package.
-c
Respect case when matching symbols.
-cmd
Treat a command (package main) like a regular package.
Otherwise package main's exported symbols are hidden
when showing the package's top-level documentation.
+ -src
+ Show the full source code for the symbol. This will
+ display the full Go source of its declaration and
+ definition, such as a function definition (including
+ the body), type declaration or enclosing const
+ block. The output may therefore include unexported
+ details.
-u
Show documentation for unexported as well as exported
symbols, methods, and fields.
diff --git a/libgo/go/cmd/go/internal/envcmd/env.go b/libgo/go/cmd/go/internal/envcmd/env.go
index afadbade38e..ae98d3999a1 100644
--- a/libgo/go/cmd/go/internal/envcmd/env.go
+++ b/libgo/go/cmd/go/internal/envcmd/env.go
@@ -115,8 +115,10 @@ func findEnv(env []cfg.EnvVar, name string) string {
// ExtraEnvVars returns environment variables that should not leak into child processes.
func ExtraEnvVars() []cfg.EnvVar {
gomod := ""
- if modload.Init(); modload.ModRoot != "" {
- gomod = filepath.Join(modload.ModRoot, "go.mod")
+ if modload.HasModRoot() {
+ gomod = filepath.Join(modload.ModRoot(), "go.mod")
+ } else if modload.Enabled() {
+ gomod = os.DevNull
}
return []cfg.EnvVar{
{Name: "GOMOD", Value: gomod},
@@ -203,7 +205,7 @@ func runEnv(cmd *base.Command, args []string) {
fmt.Printf("%s=\"%s\"\n", e.Name, e.Value)
case "plan9":
if strings.IndexByte(e.Value, '\x00') < 0 {
- fmt.Printf("%s='%s'\n", e.Name, strings.Replace(e.Value, "'", "''", -1))
+ fmt.Printf("%s='%s'\n", e.Name, strings.ReplaceAll(e.Value, "'", "''"))
} else {
v := strings.Split(e.Value, "\x00")
fmt.Printf("%s=(", e.Name)
diff --git a/libgo/go/cmd/go/internal/fix/fix.go b/libgo/go/cmd/go/internal/fix/fix.go
index aab164148ff..4d741df2b4f 100644
--- a/libgo/go/cmd/go/internal/fix/fix.go
+++ b/libgo/go/cmd/go/internal/fix/fix.go
@@ -34,7 +34,7 @@ See also: go fmt, go vet.
func runFix(cmd *base.Command, args []string) {
printed := false
for _, pkg := range load.Packages(args) {
- if modload.Enabled() && !pkg.Module.Main {
+ if modload.Enabled() && pkg.Module != nil && !pkg.Module.Main {
if !printed {
fmt.Fprintf(os.Stderr, "go: not fixing packages in dependency modules\n")
printed = true
diff --git a/libgo/go/cmd/go/internal/generate/generate.go b/libgo/go/cmd/go/internal/generate/generate.go
index 9482be98aef..7cbc448e6dd 100644
--- a/libgo/go/cmd/go/internal/generate/generate.go
+++ b/libgo/go/cmd/go/internal/generate/generate.go
@@ -161,7 +161,7 @@ func runGenerate(cmd *base.Command, args []string) {
// Even if the arguments are .go files, this loop suffices.
printed := false
for _, pkg := range load.Packages(args) {
- if modload.Enabled() && !pkg.Module.Main {
+ if modload.Enabled() && pkg.Module != nil && !pkg.Module.Main {
if !printed {
fmt.Fprintf(os.Stderr, "go: not generating in packages in dependency modules\n")
printed = true
diff --git a/libgo/go/cmd/go/internal/get/get.go b/libgo/go/cmd/go/internal/get/get.go
index e4148bceb04..a314c57160b 100644
--- a/libgo/go/cmd/go/internal/get/get.go
+++ b/libgo/go/cmd/go/internal/get/get.go
@@ -232,7 +232,7 @@ var downloadCache = map[string]bool{}
var downloadRootCache = map[string]bool{}
// download runs the download half of the get command
-// for the package named by the argument.
+// for the package or pattern named by the argument.
func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) {
if mode&load.ResolveImport != 0 {
// Caller is responsible for expanding vendor paths.
@@ -402,6 +402,23 @@ func downloadPackage(p *load.Package) error {
security = web.Insecure
}
+ // p can be either a real package, or a pseudo-package whose “import path” is
+ // actually a wildcard pattern.
+ // Trim the path at the element containing the first wildcard,
+ // and hope that it applies to the wildcarded parts too.
+ // This makes 'go get rsc.io/pdf/...' work in a fresh GOPATH.
+ importPrefix := p.ImportPath
+ if i := strings.Index(importPrefix, "..."); i >= 0 {
+ slash := strings.LastIndexByte(importPrefix[:i], '/')
+ if slash < 0 {
+ return fmt.Errorf("cannot expand ... in %q", p.ImportPath)
+ }
+ importPrefix = importPrefix[:slash]
+ }
+ if err := CheckImportPath(importPrefix); err != nil {
+ return fmt.Errorf("%s: invalid import path: %v", p.ImportPath, err)
+ }
+
if p.Internal.Build.SrcRoot != "" {
// Directory exists. Look for checkout along path to src.
vcs, rootPath, err = vcsFromDir(p.Dir, p.Internal.Build.SrcRoot)
@@ -421,7 +438,7 @@ func downloadPackage(p *load.Package) error {
}
repo = remote
if !*getF && err == nil {
- if rr, err := RepoRootForImportPath(p.ImportPath, IgnoreMod, security); err == nil {
+ if rr, err := RepoRootForImportPath(importPrefix, IgnoreMod, security); err == nil {
repo := rr.Repo
if rr.vcs.resolveRepo != nil {
resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo)
@@ -438,7 +455,7 @@ func downloadPackage(p *load.Package) error {
} else {
// Analyze the import path to determine the version control system,
// repository, and the import path for the root of the repository.
- rr, err := RepoRootForImportPath(p.ImportPath, IgnoreMod, security)
+ rr, err := RepoRootForImportPath(importPrefix, IgnoreMod, security)
if err != nil {
return err
}
diff --git a/libgo/go/cmd/go/internal/get/path.go b/libgo/go/cmd/go/internal/get/path.go
new file mode 100644
index 00000000000..d443bd28a96
--- /dev/null
+++ b/libgo/go/cmd/go/internal/get/path.go
@@ -0,0 +1,192 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package get
+
+import (
+ "fmt"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+)
+
+// The following functions are copied verbatim from cmd/go/internal/module/module.go,
+// with a change to additionally reject Windows short-names,
+// and one to accept arbitrary letters (golang.org/issue/29101).
+//
+// TODO(bcmills): After the call site for this function is backported,
+// consolidate this back down to a single copy.
+//
+// NOTE: DO NOT MERGE THESE UNTIL WE DECIDE ABOUT ARBITRARY LETTERS IN MODULE MODE.
+
+// CheckImportPath checks that an import path is valid.
+func CheckImportPath(path string) error {
+ if err := checkPath(path, false); err != nil {
+ return fmt.Errorf("malformed import path %q: %v", path, err)
+ }
+ return nil
+}
+
+// checkPath checks that a general path is valid.
+// It returns an error describing why but not mentioning path.
+// Because these checks apply to both module paths and import paths,
+// the caller is expected to add the "malformed ___ path %q: " prefix.
+// fileName indicates whether the final element of the path is a file name
+// (as opposed to a directory name).
+func checkPath(path string, fileName bool) error {
+ if !utf8.ValidString(path) {
+ return fmt.Errorf("invalid UTF-8")
+ }
+ if path == "" {
+ return fmt.Errorf("empty string")
+ }
+ if strings.Contains(path, "..") {
+ return fmt.Errorf("double dot")
+ }
+ if strings.Contains(path, "//") {
+ return fmt.Errorf("double slash")
+ }
+ if path[len(path)-1] == '/' {
+ return fmt.Errorf("trailing slash")
+ }
+ elemStart := 0
+ for i, r := range path {
+ if r == '/' {
+ if err := checkElem(path[elemStart:i], fileName); err != nil {
+ return err
+ }
+ elemStart = i + 1
+ }
+ }
+ if err := checkElem(path[elemStart:], fileName); err != nil {
+ return err
+ }
+ return nil
+}
+
+// checkElem checks whether an individual path element is valid.
+// fileName indicates whether the element is a file name (not a directory name).
+func checkElem(elem string, fileName bool) error {
+ if elem == "" {
+ return fmt.Errorf("empty path element")
+ }
+ if strings.Count(elem, ".") == len(elem) {
+ return fmt.Errorf("invalid path element %q", elem)
+ }
+ if elem[0] == '.' && !fileName {
+ return fmt.Errorf("leading dot in path element")
+ }
+ if elem[len(elem)-1] == '.' {
+ return fmt.Errorf("trailing dot in path element")
+ }
+
+ charOK := pathOK
+ if fileName {
+ charOK = fileNameOK
+ }
+ for _, r := range elem {
+ if !charOK(r) {
+ return fmt.Errorf("invalid char %q", r)
+ }
+ }
+
+ // Windows disallows a bunch of path elements, sadly.
+ // See https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file
+ short := elem
+ if i := strings.Index(short, "."); i >= 0 {
+ short = short[:i]
+ }
+ for _, bad := range badWindowsNames {
+ if strings.EqualFold(bad, short) {
+ return fmt.Errorf("disallowed path element %q", elem)
+ }
+ }
+
+ // Reject path components that look like Windows short-names.
+ // Those usually end in a tilde followed by one or more ASCII digits.
+ if tilde := strings.LastIndexByte(short, '~'); tilde >= 0 && tilde < len(short)-1 {
+ suffix := short[tilde+1:]
+ suffixIsDigits := true
+ for _, r := range suffix {
+ if r < '0' || r > '9' {
+ suffixIsDigits = false
+ break
+ }
+ }
+ if suffixIsDigits {
+ return fmt.Errorf("trailing tilde and digits in path element")
+ }
+ }
+
+ return nil
+}
+
+// pathOK reports whether r can appear in an import path element.
+//
+// NOTE: This function DIVERGES from module mode pathOK by accepting Unicode letters.
+func pathOK(r rune) bool {
+ if r < utf8.RuneSelf {
+ return r == '+' || r == '-' || r == '.' || r == '_' || r == '~' ||
+ '0' <= r && r <= '9' ||
+ 'A' <= r && r <= 'Z' ||
+ 'a' <= r && r <= 'z'
+ }
+ return unicode.IsLetter(r)
+}
+
+// fileNameOK reports whether r can appear in a file name.
+// For now we allow all Unicode letters but otherwise limit to pathOK plus a few more punctuation characters.
+// If we expand the set of allowed characters here, we have to
+// work harder at detecting potential case-folding and normalization collisions.
+// See note about "safe encoding" below.
+func fileNameOK(r rune) bool {
+ if r < utf8.RuneSelf {
+ // Entire set of ASCII punctuation, from which we remove characters:
+ // ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~
+ // We disallow some shell special characters: " ' * < > ? ` |
+ // (Note that some of those are disallowed by the Windows file system as well.)
+ // We also disallow path separators / : and \ (fileNameOK is only called on path element characters).
+ // We allow spaces (U+0020) in file names.
+ const allowed = "!#$%&()+,-.=@[]^_{}~ "
+ if '0' <= r && r <= '9' || 'A' <= r && r <= 'Z' || 'a' <= r && r <= 'z' {
+ return true
+ }
+ for i := 0; i < len(allowed); i++ {
+ if rune(allowed[i]) == r {
+ return true
+ }
+ }
+ return false
+ }
+ // It may be OK to add more ASCII punctuation here, but only carefully.
+ // For example Windows disallows < > \, and macOS disallows :, so we must not allow those.
+ return unicode.IsLetter(r)
+}
+
+// badWindowsNames are the reserved file path elements on Windows.
+// See https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file
+var badWindowsNames = []string{
+ "CON",
+ "PRN",
+ "AUX",
+ "NUL",
+ "COM1",
+ "COM2",
+ "COM3",
+ "COM4",
+ "COM5",
+ "COM6",
+ "COM7",
+ "COM8",
+ "COM9",
+ "LPT1",
+ "LPT2",
+ "LPT3",
+ "LPT4",
+ "LPT5",
+ "LPT6",
+ "LPT7",
+ "LPT8",
+ "LPT9",
+}
diff --git a/libgo/go/cmd/go/internal/get/vcs.go b/libgo/go/cmd/go/internal/get/vcs.go
index 5cd164f2ff3..a7a2ba32cc3 100644
--- a/libgo/go/cmd/go/internal/get/vcs.go
+++ b/libgo/go/cmd/go/internal/get/vcs.go
@@ -647,14 +647,7 @@ const (
func RepoRootForImportPath(importPath string, mod ModuleMode, security web.SecurityMode) (*RepoRoot, error) {
rr, err := repoRootFromVCSPaths(importPath, "", security, vcsPaths)
if err == errUnknownSite {
- // If there are wildcards, look up the thing before the wildcard,
- // hoping it applies to the wildcarded parts too.
- // This makes 'go get rsc.io/pdf/...' work in a fresh GOPATH.
- lookup := strings.TrimSuffix(importPath, "/...")
- if i := strings.Index(lookup, "/.../"); i >= 0 {
- lookup = lookup[:i]
- }
- rr, err = repoRootForImportDynamic(lookup, mod, security)
+ rr, err = repoRootForImportDynamic(importPath, mod, security)
if err != nil {
err = fmt.Errorf("unrecognized import path %q (%v)", importPath, err)
}
@@ -667,6 +660,7 @@ func RepoRootForImportPath(importPath string, mod ModuleMode, security web.Secur
}
}
+ // Should have been taken care of above, but make sure.
if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.Root, "...") {
// Do not allow wildcards in the repo root.
rr = nil
@@ -903,16 +897,16 @@ type metaImport struct {
Prefix, VCS, RepoRoot string
}
-func splitPathHasPrefix(path, prefix []string) bool {
- if len(path) < len(prefix) {
+// pathPrefix reports whether sub is a prefix of s,
+// only considering entire path components.
+func pathPrefix(s, sub string) bool {
+ // strings.HasPrefix is necessary but not sufficient.
+ if !strings.HasPrefix(s, sub) {
return false
}
- for i, p := range prefix {
- if path[i] != p {
- return false
- }
- }
- return true
+ // The remainder after the prefix must either be empty or start with a slash.
+ rem := s[len(sub):]
+ return rem == "" || rem[0] == '/'
}
// A ImportMismatchError is returned where metaImport/s are present
@@ -935,13 +929,10 @@ func (m ImportMismatchError) Error() string {
// errNoMatch is returned if none match.
func matchGoImport(imports []metaImport, importPath string) (metaImport, error) {
match := -1
- imp := strings.Split(importPath, "/")
errImportMismatch := ImportMismatchError{importPath: importPath}
for i, im := range imports {
- pre := strings.Split(im.Prefix, "/")
-
- if !splitPathHasPrefix(imp, pre) {
+ if !pathPrefix(importPath, im.Prefix) {
errImportMismatch.mismatches = append(errImportMismatch.mismatches, im.Prefix)
continue
}
@@ -966,10 +957,14 @@ func matchGoImport(imports []metaImport, importPath string) (metaImport, error)
// expand rewrites s to replace {k} with match[k] for each key k in match.
func expand(match map[string]string, s string) string {
+ // We want to replace each match exactly once, and the result of expansion
+ // must not depend on the iteration order through the map.
+ // A strings.Replacer has exactly the properties we're looking for.
+ oldNew := make([]string, 0, 2*len(match))
for k, v := range match {
- s = strings.Replace(s, "{"+k+"}", v, -1)
+ oldNew = append(oldNew, "{"+k+"}", v)
}
- return s
+ return strings.NewReplacer(oldNew...).Replace(s)
}
// vcsPaths defines the meaning of import paths referring to
diff --git a/libgo/go/cmd/go/internal/help/help.go b/libgo/go/cmd/go/internal/help/help.go
index a80afe36c41..312a29590f4 100644
--- a/libgo/go/cmd/go/internal/help/help.go
+++ b/libgo/go/cmd/go/internal/help/help.go
@@ -20,16 +20,16 @@ import (
)
// Help implements the 'help' command.
-func Help(args []string) {
+func Help(w io.Writer, args []string) {
// 'go help documentation' generates doc.go.
if len(args) == 1 && args[0] == "documentation" {
- fmt.Println("// Copyright 2011 The Go Authors. All rights reserved.")
- fmt.Println("// Use of this source code is governed by a BSD-style")
- fmt.Println("// license that can be found in the LICENSE file.")
- fmt.Println()
- fmt.Println("// Code generated by mkalldocs.sh; DO NOT EDIT.")
- fmt.Println("// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.")
- fmt.Println()
+ fmt.Fprintln(w, "// Copyright 2011 The Go Authors. All rights reserved.")
+ fmt.Fprintln(w, "// Use of this source code is governed by a BSD-style")
+ fmt.Fprintln(w, "// license that can be found in the LICENSE file.")
+ fmt.Fprintln(w)
+ fmt.Fprintln(w, "// Code generated by mkalldocs.sh; DO NOT EDIT.")
+ fmt.Fprintln(w, "// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.")
+ fmt.Fprintln(w)
buf := new(bytes.Buffer)
PrintUsage(buf, base.Go)
usage := &base.Command{Long: buf.String()}
@@ -42,8 +42,8 @@ func Help(args []string) {
cmds = append(cmds, cmd)
cmds = append(cmds, cmd.Commands...)
}
- tmpl(&commentWriter{W: os.Stdout}, documentationTemplate, cmds)
- fmt.Println("package main")
+ tmpl(&commentWriter{W: w}, documentationTemplate, cmds)
+ fmt.Fprintln(w, "package main")
return
}
diff --git a/libgo/go/cmd/go/internal/help/helpdoc.go b/libgo/go/cmd/go/internal/help/helpdoc.go
index e2c4e61615b..973bfbc611d 100644
--- a/libgo/go/cmd/go/internal/help/helpdoc.go
+++ b/libgo/go/cmd/go/internal/help/helpdoc.go
@@ -266,7 +266,7 @@ listed in the GOPATH environment variable.
(See 'go help gopath-get' and 'go help gopath'.)
When using modules, downloaded packages are stored in the module cache.
-(See 'go help modules-get' and 'go help goproxy'.)
+(See 'go help module-get' and 'go help goproxy'.)
When using modules, an additional variant of the go-import meta tag is
recognized and is preferred over those listing version control systems.
@@ -509,9 +509,7 @@ General-purpose environment variables:
Each entry in the GOFLAGS list must be a standalone flag.
Because the entries are space-separated, flag values must
-not contain spaces. In some cases, you can provide multiple flag
-values instead: for example, to set '-ldflags=-s -w'
-you can use 'GOFLAGS=-ldflags=-s -ldflags=-w'.
+not contain spaces.
Environment variables for use with cgo:
@@ -546,6 +544,10 @@ Environment variables for use with cgo:
The command to use to compile C++ code.
PKG_CONFIG
Path to pkg-config tool.
+ AR
+ The command to use to manipulate library archives when
+ building with the gccgo compiler.
+ The default is 'ar'.
Architecture-specific environment variables:
diff --git a/libgo/go/cmd/go/internal/imports/build.go b/libgo/go/cmd/go/internal/imports/build.go
index d1adf9440cb..ddf425b0204 100644
--- a/libgo/go/cmd/go/internal/imports/build.go
+++ b/libgo/go/cmd/go/internal/imports/build.go
@@ -207,5 +207,5 @@ func init() {
}
}
-const goosList = "android darwin dragonfly freebsd js linux nacl netbsd openbsd plan9 solaris windows zos "
+const goosList = "aix android darwin dragonfly freebsd hurd js linux nacl netbsd openbsd plan9 solaris windows zos "
const goarchList = "386 amd64 amd64p32 arm armbe arm64 arm64be ppc64 ppc64le mips mipsle mips64 mips64le mips64p32 mips64p32le ppc riscv riscv64 s390 s390x sparc sparc64 wasm "
diff --git a/libgo/go/cmd/go/internal/imports/scan.go b/libgo/go/cmd/go/internal/imports/scan.go
index d944e95724e..966a38cfef3 100644
--- a/libgo/go/cmd/go/internal/imports/scan.go
+++ b/libgo/go/cmd/go/internal/imports/scan.go
@@ -22,6 +22,16 @@ func ScanDir(dir string, tags map[string]bool) ([]string, []string, error) {
var files []string
for _, info := range infos {
name := info.Name()
+
+ // If the directory entry is a symlink, stat it to obtain the info for the
+ // link target instead of the link itself.
+ if info.Mode()&os.ModeSymlink != 0 {
+ info, err = os.Stat(name)
+ if err != nil {
+ continue // Ignore broken symlinks.
+ }
+ }
+
if info.Mode().IsRegular() && !strings.HasPrefix(name, "_") && strings.HasSuffix(name, ".go") && MatchFile(name, tags) {
files = append(files, filepath.Join(dir, name))
}
diff --git a/libgo/go/cmd/go/internal/load/pkg.go b/libgo/go/cmd/go/internal/load/pkg.go
index b6c90378881..543250e86c1 100644
--- a/libgo/go/cmd/go/internal/load/pkg.go
+++ b/libgo/go/cmd/go/internal/load/pkg.go
@@ -440,6 +440,10 @@ const (
// this package, as part of a bigger load operation, and by GOPATH-based "go get".
// TODO(rsc): When GOPATH-based "go get" is removed, unexport this function.
func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) *Package {
+ if path == "" {
+ panic("LoadImport called with empty package path")
+ }
+
stk.Push(path)
defer stk.Pop()
@@ -999,10 +1003,12 @@ func disallowInternal(srcDir string, importer *Package, importerPath string, p *
} else {
// p is in a module, so make it available based on the importer's import path instead
// of the file path (https://golang.org/issue/23970).
- if importerPath == "." {
+ if importer.Internal.CmdlineFiles {
// The importer is a list of command-line files.
// Pretend that the import path is the import path of the
// directory containing them.
+ // If the directory is outside the main module, this will resolve to ".",
+ // which is not a prefix of any valid module.
importerPath = ModDirImportPath(importer.Dir)
}
parentOfInternal := p.ImportPath[:i]
@@ -1053,20 +1059,6 @@ func disallowVendor(srcDir string, importer *Package, importerPath, path string,
return p
}
- // Modules must not import vendor packages in the standard library,
- // but the usual vendor visibility check will not catch them
- // because the module loader presents them with an ImportPath starting
- // with "golang_org/" instead of "vendor/".
- if p.Standard && !importer.Standard && strings.HasPrefix(p.ImportPath, "golang_org") {
- perr := *p
- perr.Error = &PackageError{
- ImportStack: stk.Copy(),
- Err: "use of vendored package " + path + " not allowed",
- }
- perr.Incomplete = true
- return &perr
- }
-
if perr := disallowVendorVisibility(srcDir, p, stk); perr != p {
return perr
}
@@ -1345,6 +1337,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
// SWIG adds imports of some standard packages.
if p.UsesSwig() {
+ addImport("unsafe", true)
if cfg.BuildContext.Compiler != "gccgo" {
addImport("runtime/cgo", true)
}
@@ -1530,9 +1523,13 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
}
if cfg.ModulesEnabled {
- p.Module = ModPackageModuleInfo(p.ImportPath)
+ mainPath := p.ImportPath
+ if p.Internal.CmdlineFiles {
+ mainPath = "command-line-arguments"
+ }
+ p.Module = ModPackageModuleInfo(mainPath)
if p.Name == "main" {
- p.Internal.BuildInfo = ModPackageBuildInfo(p.ImportPath, p.Deps)
+ p.Internal.BuildInfo = ModPackageBuildInfo(mainPath, p.Deps)
}
}
}
@@ -1756,6 +1753,9 @@ func LoadPackageNoFlags(arg string, stk *ImportStack) *Package {
// loadPackage accepts pseudo-paths beginning with cmd/ to denote commands
// in the Go command directory, as well as paths to those directories.
func loadPackage(arg string, stk *ImportStack) *Package {
+ if arg == "" {
+ panic("loadPackage called with empty package path")
+ }
if build.IsLocalImport(arg) {
dir := arg
if !filepath.IsAbs(dir) {
@@ -1779,9 +1779,6 @@ func loadPackage(arg string, stk *ImportStack) *Package {
bp.ImportPath = arg
bp.Goroot = true
bp.BinDir = cfg.GOROOTbin
- if cfg.GOROOTbin != "" {
- bp.BinDir = cfg.GOROOTbin
- }
bp.Root = cfg.GOROOT
bp.SrcRoot = cfg.GOROOTsrc
p := new(Package)
@@ -1854,6 +1851,9 @@ func PackagesAndErrors(patterns []string) []*Package {
for _, m := range matches {
for _, pkg := range m.Pkgs {
+ if pkg == "" {
+ panic(fmt.Sprintf("ImportPaths returned empty package for pattern %s", m.Pattern))
+ }
p := loadPackage(pkg, &stk)
p.Match = append(p.Match, m.Pattern)
p.Internal.CmdlinePkg = true
@@ -1996,11 +1996,6 @@ func GoFilesPackage(gofiles []string) *Package {
}
bp, err := ctxt.ImportDir(dir, 0)
- if ModDirImportPath != nil {
- // Use the effective import path of the directory
- // for deciding visibility during pkg.load.
- bp.ImportPath = ModDirImportPath(dir)
- }
pkg := new(Package)
pkg.Internal.Local = true
pkg.Internal.CmdlineFiles = true
diff --git a/libgo/go/cmd/go/internal/load/test.go b/libgo/go/cmd/go/internal/load/test.go
index 0eab21b1761..5f9daa49578 100644
--- a/libgo/go/cmd/go/internal/load/test.go
+++ b/libgo/go/cmd/go/internal/load/test.go
@@ -227,6 +227,12 @@ func GetTestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Pac
}
}
+ allTestImports := make([]*Package, 0, len(pmain.Internal.Imports)+len(imports)+len(ximports))
+ allTestImports = append(allTestImports, pmain.Internal.Imports...)
+ allTestImports = append(allTestImports, imports...)
+ allTestImports = append(allTestImports, ximports...)
+ setToolFlags(allTestImports...)
+
// Do initial scan for metadata needed for writing _testmain.go
// Use that metadata to update the list of imports for package main.
// The list of imports is used by recompileForTest and by the loop
diff --git a/libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock.go b/libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock.go
new file mode 100644
index 00000000000..aba3eed7767
--- /dev/null
+++ b/libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock.go
@@ -0,0 +1,98 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package filelock provides a platform-independent API for advisory file
+// locking. Calls to functions in this package on platforms that do not support
+// advisory locks will return errors for which IsNotSupported returns true.
+package filelock
+
+import (
+ "errors"
+ "os"
+)
+
+// A File provides the minimal set of methods required to lock an open file.
+// File implementations must be usable as map keys.
+// The usual implementation is *os.File.
+type File interface {
+ // Name returns the name of the file.
+ Name() string
+
+ // Fd returns a valid file descriptor.
+ // (If the File is an *os.File, it must not be closed.)
+ Fd() uintptr
+
+ // Stat returns the FileInfo structure describing file.
+ Stat() (os.FileInfo, error)
+}
+
+// Lock places an advisory write lock on the file, blocking until it can be
+// locked.
+//
+// If Lock returns nil, no other process will be able to place a read or write
+// lock on the file until this process exits, closes f, or calls Unlock on it.
+//
+// If f's descriptor is already read- or write-locked, the behavior of Lock is
+// unspecified.
+//
+// Closing the file may or may not release the lock promptly. Callers should
+// ensure that Unlock is always called when Lock succeeds.
+func Lock(f File) error {
+ return lock(f, writeLock)
+}
+
+// RLock places an advisory read lock on the file, blocking until it can be locked.
+//
+// If RLock returns nil, no other process will be able to place a write lock on
+// the file until this process exits, closes f, or calls Unlock on it.
+//
+// If f is already read- or write-locked, the behavior of RLock is unspecified.
+//
+// Closing the file may or may not release the lock promptly. Callers should
+// ensure that Unlock is always called if RLock succeeds.
+func RLock(f File) error {
+ return lock(f, readLock)
+}
+
+// Unlock removes an advisory lock placed on f by this process.
+//
+// The caller must not attempt to unlock a file that is not locked.
+func Unlock(f File) error {
+ return unlock(f)
+}
+
+// String returns the name of the function corresponding to lt
+// (Lock, RLock, or Unlock).
+func (lt lockType) String() string {
+ switch lt {
+ case readLock:
+ return "RLock"
+ case writeLock:
+ return "Lock"
+ default:
+ return "Unlock"
+ }
+}
+
+// IsNotSupported returns a boolean indicating whether the error is known to
+// report that a function is not supported (possibly for a specific input).
+// It is satisfied by ErrNotSupported as well as some syscall errors.
+func IsNotSupported(err error) bool {
+ return isNotSupported(underlyingError(err))
+}
+
+var ErrNotSupported = errors.New("operation not supported")
+
+// underlyingError returns the underlying error for known os error types.
+func underlyingError(err error) error {
+ switch err := err.(type) {
+ case *os.PathError:
+ return err.Err
+ case *os.LinkError:
+ return err.Err
+ case *os.SyscallError:
+ return err.Err
+ }
+ return err
+}
diff --git a/libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go b/libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go
new file mode 100644
index 00000000000..2831975c0c6
--- /dev/null
+++ b/libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go
@@ -0,0 +1,159 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build aix solaris
+
+// This code implements the filelock API using POSIX 'fcntl' locks, which attach
+// to an (inode, process) pair rather than a file descriptor. To avoid unlocking
+// files prematurely when the same file is opened through different descriptors,
+// we allow only one read-lock at a time.
+//
+// Most platforms provide some alternative API, such as an 'flock' system call
+// or an F_OFD_SETLK command for 'fcntl', that allows for better concurrency and
+// does not require per-inode bookkeeping in the application.
+//
+// TODO(bcmills): If we add a build tag for Illumos (see golang.org/issue/20603)
+// then Illumos should use F_OFD_SETLK, and the resulting code would be as
+// simple as filelock_unix.go. We will still need the code in this file for AIX
+// or as long as Oracle Solaris provides only F_SETLK.
+
+package filelock
+
+import (
+ "errors"
+ "io"
+ "os"
+ "sync"
+ "syscall"
+)
+
+type lockType int16
+
+const (
+ readLock lockType = syscall.F_RDLCK
+ writeLock lockType = syscall.F_WRLCK
+)
+
+type inode = uint64 // type of syscall.Stat_t.Ino
+
+type inodeLock struct {
+ owner File
+ queue []<-chan File
+}
+
+type token struct{}
+
+var (
+ mu sync.Mutex
+ inodes = map[File]inode{}
+ locks = map[inode]inodeLock{}
+)
+
+func lock(f File, lt lockType) (err error) {
+ // POSIX locks apply per inode and process, and the lock for an inode is
+ // released when *any* descriptor for that inode is closed. So we need to
+ // synchronize access to each inode internally, and must serialize lock and
+ // unlock calls that refer to the same inode through different descriptors.
+ fi, err := f.Stat()
+ if err != nil {
+ return err
+ }
+ ino := fi.Sys().(*syscall.Stat_t).Ino
+
+ mu.Lock()
+ if i, dup := inodes[f]; dup && i != ino {
+ mu.Unlock()
+ return &os.PathError{
+ Op: lt.String(),
+ Path: f.Name(),
+ Err: errors.New("inode for file changed since last Lock or RLock"),
+ }
+ }
+ inodes[f] = ino
+
+ var wait chan File
+ l := locks[ino]
+ if l.owner == f {
+ // This file already owns the lock, but the call may change its lock type.
+ } else if l.owner == nil {
+ // No owner: it's ours now.
+ l.owner = f
+ } else {
+ // Already owned: add a channel to wait on.
+ wait = make(chan File)
+ l.queue = append(l.queue, wait)
+ }
+ locks[ino] = l
+ mu.Unlock()
+
+ if wait != nil {
+ wait <- f
+ }
+
+ err = setlkw(f.Fd(), lt)
+
+ if err != nil {
+ unlock(f)
+ return &os.PathError{
+ Op: lt.String(),
+ Path: f.Name(),
+ Err: err,
+ }
+ }
+
+ return nil
+}
+
+func unlock(f File) error {
+ var owner File
+
+ mu.Lock()
+ ino, ok := inodes[f]
+ if ok {
+ owner = locks[ino].owner
+ }
+ mu.Unlock()
+
+ if owner != f {
+ panic("unlock called on a file that is not locked")
+ }
+
+ err := setlkw(f.Fd(), syscall.F_UNLCK)
+
+ mu.Lock()
+ l := locks[ino]
+ if len(l.queue) == 0 {
+ // No waiters: remove the map entry.
+ delete(locks, ino)
+ } else {
+ // The first waiter is sending us their file now.
+ // Receive it and update the queue.
+ l.owner = <-l.queue[0]
+ l.queue = l.queue[1:]
+ locks[ino] = l
+ }
+ delete(inodes, f)
+ mu.Unlock()
+
+ return err
+}
+
+// setlkw calls FcntlFlock with F_SETLKW for the entire file indicated by fd.
+func setlkw(fd uintptr, lt lockType) error {
+ for {
+ err := syscall.FcntlFlock(fd, syscall.F_SETLKW, &syscall.Flock_t{
+ Type: int16(lt),
+ Whence: io.SeekStart,
+ Start: 0,
+ Len: 0, // All bytes.
+ })
+ if err != syscall.EINTR {
+ return err
+ }
+ }
+}
+
+func isNotSupported(err error) bool {
+ return err == syscall.ENOSYS || err == syscall.ENOTSUP || err == syscall.EOPNOTSUPP || err == ErrNotSupported
+}
diff --git a/libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock_other.go b/libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock_other.go
new file mode 100644
index 00000000000..107611e1ce8
--- /dev/null
+++ b/libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock_other.go
@@ -0,0 +1,36 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!plan9,!solaris,!windows
+
+package filelock
+
+import "os"
+
+type lockType int8
+
+const (
+ readLock = iota + 1
+ writeLock
+)
+
+func lock(f File, lt lockType) error {
+ return &os.PathError{
+ Op: lt.String(),
+ Path: f.Name(),
+ Err: ErrNotSupported,
+ }
+}
+
+func unlock(f File) error {
+ return &os.PathError{
+ Op: "Unlock",
+ Path: f.Name(),
+ Err: ErrNotSupported,
+ }
+}
+
+func isNotSupported(err error) bool {
+ return err == ErrNotSupported
+}
diff --git a/libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock_plan9.go b/libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock_plan9.go
new file mode 100644
index 00000000000..afdffe323fc
--- /dev/null
+++ b/libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock_plan9.go
@@ -0,0 +1,38 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build plan9
+
+package filelock
+
+import (
+ "os"
+)
+
+type lockType int8
+
+const (
+ readLock = iota + 1
+ writeLock
+)
+
+func lock(f File, lt lockType) error {
+ return &os.PathError{
+ Op: lt.String(),
+ Path: f.Name(),
+ Err: ErrNotSupported,
+ }
+}
+
+func unlock(f File) error {
+ return &os.PathError{
+ Op: "Unlock",
+ Path: f.Name(),
+ Err: ErrNotSupported,
+ }
+}
+
+func isNotSupported(err error) bool {
+ return err == ErrNotSupported
+}
diff --git a/libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock_test.go b/libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock_test.go
new file mode 100644
index 00000000000..aa67093a48a
--- /dev/null
+++ b/libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock_test.go
@@ -0,0 +1,209 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !js,!nacl,!plan9
+
+package filelock_test
+
+import (
+ "fmt"
+ "internal/testenv"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "testing"
+ "time"
+
+ "cmd/go/internal/lockedfile/internal/filelock"
+)
+
+func lock(t *testing.T, f *os.File) {
+ t.Helper()
+ err := filelock.Lock(f)
+ t.Logf("Lock(fd %d) = %v", f.Fd(), err)
+ if err != nil {
+ t.Fail()
+ }
+}
+
+func rLock(t *testing.T, f *os.File) {
+ t.Helper()
+ err := filelock.RLock(f)
+ t.Logf("RLock(fd %d) = %v", f.Fd(), err)
+ if err != nil {
+ t.Fail()
+ }
+}
+
+func unlock(t *testing.T, f *os.File) {
+ t.Helper()
+ err := filelock.Unlock(f)
+ t.Logf("Unlock(fd %d) = %v", f.Fd(), err)
+ if err != nil {
+ t.Fail()
+ }
+}
+
+func mustTempFile(t *testing.T) (f *os.File, remove func()) {
+ t.Helper()
+
+ base := filepath.Base(t.Name())
+ f, err := ioutil.TempFile("", base)
+ if err != nil {
+ t.Fatalf(`ioutil.TempFile("", %q) = %v`, base, err)
+ }
+ t.Logf("fd %d = %s", f.Fd(), f.Name())
+
+ return f, func() {
+ f.Close()
+ os.Remove(f.Name())
+ }
+}
+
+func mustOpen(t *testing.T, name string) *os.File {
+ t.Helper()
+
+ f, err := os.OpenFile(name, os.O_RDWR, 0)
+ if err != nil {
+ t.Fatalf("os.Open(%q) = %v", name, err)
+ }
+
+ t.Logf("fd %d = os.Open(%q)", f.Fd(), name)
+ return f
+}
+
+const (
+ quiescent = 10 * time.Millisecond
+ probablyStillBlocked = 10 * time.Second
+)
+
+func mustBlock(t *testing.T, op string, f *os.File) (wait func(*testing.T)) {
+ t.Helper()
+
+ desc := fmt.Sprintf("%s(fd %d)", op, f.Fd())
+
+ done := make(chan struct{})
+ go func() {
+ t.Helper()
+ switch op {
+ case "Lock":
+ lock(t, f)
+ case "RLock":
+ rLock(t, f)
+ default:
+ panic("invalid op: " + op)
+ }
+ close(done)
+ }()
+
+ select {
+ case <-done:
+ t.Fatalf("%s unexpectedly did not block", desc)
+ return nil
+
+ case <-time.After(quiescent):
+ t.Logf("%s is blocked (as expected)", desc)
+ return func(t *testing.T) {
+ t.Helper()
+ select {
+ case <-time.After(probablyStillBlocked):
+ t.Fatalf("%s is unexpectedly still blocked", desc)
+ case <-done:
+ }
+ }
+ }
+}
+
+func TestLockExcludesLock(t *testing.T) {
+ t.Parallel()
+
+ f, remove := mustTempFile(t)
+ defer remove()
+
+ other := mustOpen(t, f.Name())
+ defer other.Close()
+
+ lock(t, f)
+ lockOther := mustBlock(t, "Lock", other)
+ unlock(t, f)
+ lockOther(t)
+ unlock(t, other)
+}
+
+func TestLockExcludesRLock(t *testing.T) {
+ t.Parallel()
+
+ f, remove := mustTempFile(t)
+ defer remove()
+
+ other := mustOpen(t, f.Name())
+ defer other.Close()
+
+ lock(t, f)
+ rLockOther := mustBlock(t, "RLock", other)
+ unlock(t, f)
+ rLockOther(t)
+ unlock(t, other)
+}
+
+func TestRLockExcludesOnlyLock(t *testing.T) {
+ t.Parallel()
+
+ f, remove := mustTempFile(t)
+ defer remove()
+ rLock(t, f)
+
+ f2 := mustOpen(t, f.Name())
+ defer f2.Close()
+
+ if runtime.GOOS == "solaris" || runtime.GOOS == "aix" {
+ // When using POSIX locks (as on Solaris), we can't safely read-lock the
+ // same inode through two different descriptors at the same time: when the
+ // first descriptor is closed, the second descriptor would still be open but
+ // silently unlocked. So a second RLock must block instead of proceeding.
+ lockF2 := mustBlock(t, "RLock", f2)
+ unlock(t, f)
+ lockF2(t)
+ } else {
+ rLock(t, f2)
+ }
+
+ other := mustOpen(t, f.Name())
+ defer other.Close()
+ lockOther := mustBlock(t, "Lock", other)
+
+ unlock(t, f2)
+ if runtime.GOOS != "solaris" && runtime.GOOS != "aix" {
+ unlock(t, f)
+ }
+ lockOther(t)
+ unlock(t, other)
+}
+
+func TestLockNotDroppedByExecCommand(t *testing.T) {
+ testenv.MustHaveExec(t)
+
+ f, remove := mustTempFile(t)
+ defer remove()
+
+ lock(t, f)
+
+ other := mustOpen(t, f.Name())
+ defer other.Close()
+
+ // Some kinds of file locks are dropped when a duplicated or forked file
+ // descriptor is unlocked. Double-check that the approach used by os/exec does
+ // not accidentally drop locks.
+ cmd := exec.Command(os.Args[0], "-test.run=^$")
+ if err := cmd.Run(); err != nil {
+ t.Fatalf("exec failed: %v", err)
+ }
+
+ lockOther := mustBlock(t, "Lock", other)
+ unlock(t, f)
+ lockOther(t)
+ unlock(t, other)
+}
diff --git a/libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock_unix.go b/libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock_unix.go
new file mode 100644
index 00000000000..00c42628322
--- /dev/null
+++ b/libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock_unix.go
@@ -0,0 +1,44 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd
+
+package filelock
+
+import (
+ "os"
+ "syscall"
+)
+
+type lockType int16
+
+const (
+ readLock lockType = syscall.LOCK_SH
+ writeLock lockType = syscall.LOCK_EX
+)
+
+func lock(f File, lt lockType) (err error) {
+ for {
+ err = syscall.Flock(int(f.Fd()), int(lt))
+ if err != syscall.EINTR {
+ break
+ }
+ }
+ if err != nil {
+ return &os.PathError{
+ Op: lt.String(),
+ Path: f.Name(),
+ Err: err,
+ }
+ }
+ return nil
+}
+
+func unlock(f File) error {
+ return lock(f, syscall.LOCK_UN)
+}
+
+func isNotSupported(err error) bool {
+ return err == syscall.ENOSYS || err == syscall.ENOTSUP || err == syscall.EOPNOTSUPP || err == ErrNotSupported
+}
diff --git a/libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock_windows.go b/libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock_windows.go
new file mode 100644
index 00000000000..43e85e450ec
--- /dev/null
+++ b/libgo/go/cmd/go/internal/lockedfile/internal/filelock/filelock_windows.go
@@ -0,0 +1,66 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package filelock
+
+import (
+ "internal/syscall/windows"
+ "os"
+ "syscall"
+)
+
+type lockType uint32
+
+const (
+ readLock lockType = 0
+ writeLock lockType = windows.LOCKFILE_EXCLUSIVE_LOCK
+)
+
+const (
+ reserved = 0
+ allBytes = ^uint32(0)
+)
+
+func lock(f File, lt lockType) error {
+ // Per https://golang.org/issue/19098, “Programs currently expect the Fd
+ // method to return a handle that uses ordinary synchronous I/O.”
+ // However, LockFileEx still requires an OVERLAPPED structure,
+ // which contains the file offset of the beginning of the lock range.
+ // We want to lock the entire file, so we leave the offset as zero.
+ ol := new(syscall.Overlapped)
+
+ err := windows.LockFileEx(syscall.Handle(f.Fd()), uint32(lt), reserved, allBytes, allBytes, ol)
+ if err != nil {
+ return &os.PathError{
+ Op: lt.String(),
+ Path: f.Name(),
+ Err: err,
+ }
+ }
+ return nil
+}
+
+func unlock(f File) error {
+ ol := new(syscall.Overlapped)
+ err := windows.UnlockFileEx(syscall.Handle(f.Fd()), reserved, allBytes, allBytes, ol)
+ if err != nil {
+ return &os.PathError{
+ Op: "Unlock",
+ Path: f.Name(),
+ Err: err,
+ }
+ }
+ return nil
+}
+
+func isNotSupported(err error) bool {
+ switch err {
+ case windows.ERROR_NOT_SUPPORTED, windows.ERROR_CALL_NOT_IMPLEMENTED, ErrNotSupported:
+ return true
+ default:
+ return false
+ }
+}
diff --git a/libgo/go/cmd/go/internal/lockedfile/lockedfile.go b/libgo/go/cmd/go/internal/lockedfile/lockedfile.go
new file mode 100644
index 00000000000..bb184b1085e
--- /dev/null
+++ b/libgo/go/cmd/go/internal/lockedfile/lockedfile.go
@@ -0,0 +1,122 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package lockedfile creates and manipulates files whose contents should only
+// change atomically.
+package lockedfile
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "runtime"
+)
+
+// A File is a locked *os.File.
+//
+// Closing the file releases the lock.
+//
+// If the program exits while a file is locked, the operating system releases
+// the lock but may not do so promptly: callers must ensure that all locked
+// files are closed before exiting.
+type File struct {
+ osFile
+ closed bool
+}
+
+// osFile embeds a *os.File while keeping the pointer itself unexported.
+// (When we close a File, it must be the same file descriptor that we opened!)
+type osFile struct {
+ *os.File
+}
+
+// OpenFile is like os.OpenFile, but returns a locked file.
+// If flag includes os.O_WRONLY or os.O_RDWR, the file is write-locked;
+// otherwise, it is read-locked.
+func OpenFile(name string, flag int, perm os.FileMode) (*File, error) {
+ var (
+ f = new(File)
+ err error
+ )
+ f.osFile.File, err = openFile(name, flag, perm)
+ if err != nil {
+ return nil, err
+ }
+
+ // Although the operating system will drop locks for open files when the go
+ // command exits, we want to hold locks for as little time as possible, and we
+ // especially don't want to leave a file locked after we're done with it. Our
+ // Close method is what releases the locks, so use a finalizer to report
+ // missing Close calls on a best-effort basis.
+ runtime.SetFinalizer(f, func(f *File) {
+ panic(fmt.Sprintf("lockedfile.File %s became unreachable without a call to Close", f.Name()))
+ })
+
+ return f, nil
+}
+
+// Open is like os.Open, but returns a read-locked file.
+func Open(name string) (*File, error) {
+ return OpenFile(name, os.O_RDONLY, 0)
+}
+
+// Create is like os.Create, but returns a write-locked file.
+func Create(name string) (*File, error) {
+ return OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
+}
+
+// Edit creates the named file with mode 0666 (before umask),
+// but does not truncate existing contents.
+//
+// If Edit succeeds, methods on the returned File can be used for I/O.
+// The associated file descriptor has mode O_RDWR and the file is write-locked.
+func Edit(name string) (*File, error) {
+ return OpenFile(name, os.O_RDWR|os.O_CREATE, 0666)
+}
+
+// Close unlocks and closes the underlying file.
+//
+// Close may be called multiple times; all calls after the first will return a
+// non-nil error.
+func (f *File) Close() error {
+ if f.closed {
+ return &os.PathError{
+ Op: "close",
+ Path: f.Name(),
+ Err: os.ErrClosed,
+ }
+ }
+ f.closed = true
+
+ err := closeFile(f.osFile.File)
+ runtime.SetFinalizer(f, nil)
+ return err
+}
+
+// Read opens the named file with a read-lock and returns its contents.
+func Read(name string) ([]byte, error) {
+ f, err := Open(name)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ return ioutil.ReadAll(f)
+}
+
+// Write opens the named file (creating it with the given permissions if needed),
+// then write-locks it and overwrites it with the given content.
+func Write(name string, content io.Reader, perm os.FileMode) (err error) {
+ f, err := OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
+ if err != nil {
+ return err
+ }
+
+ _, err = io.Copy(f, content)
+ if closeErr := f.Close(); err == nil {
+ err = closeErr
+ }
+ return err
+}
diff --git a/libgo/go/cmd/go/internal/lockedfile/lockedfile_filelock.go b/libgo/go/cmd/go/internal/lockedfile/lockedfile_filelock.go
new file mode 100644
index 00000000000..f63dd8664b0
--- /dev/null
+++ b/libgo/go/cmd/go/internal/lockedfile/lockedfile_filelock.go
@@ -0,0 +1,64 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !plan9
+
+package lockedfile
+
+import (
+ "os"
+
+ "cmd/go/internal/lockedfile/internal/filelock"
+)
+
+func openFile(name string, flag int, perm os.FileMode) (*os.File, error) {
+ // On BSD systems, we could add the O_SHLOCK or O_EXLOCK flag to the OpenFile
+ // call instead of locking separately, but we have to support separate locking
+ // calls for Linux and Windows anyway, so it's simpler to use that approach
+ // consistently.
+
+ f, err := os.OpenFile(name, flag&^os.O_TRUNC, perm)
+ if err != nil {
+ return nil, err
+ }
+
+ switch flag & (os.O_RDONLY | os.O_WRONLY | os.O_RDWR) {
+ case os.O_WRONLY, os.O_RDWR:
+ err = filelock.Lock(f)
+ default:
+ err = filelock.RLock(f)
+ }
+ if err != nil {
+ f.Close()
+ return nil, err
+ }
+
+ if flag&os.O_TRUNC == os.O_TRUNC {
+ if err := f.Truncate(0); err != nil {
+ // The documentation for os.O_TRUNC says “if possible, truncate file when
+ // opened”, but doesn't define “possible” (golang.org/issue/28699).
+ // We'll treat regular files (and symlinks to regular files) as “possible”
+ // and ignore errors for the rest.
+ if fi, statErr := f.Stat(); statErr != nil || fi.Mode().IsRegular() {
+ filelock.Unlock(f)
+ f.Close()
+ return nil, err
+ }
+ }
+ }
+
+ return f, nil
+}
+
+func closeFile(f *os.File) error {
+ // Since locking syscalls operate on file descriptors, we must unlock the file
+ // while the descriptor is still valid — that is, before the file is closed —
+ // and avoid unlocking files that are already closed.
+ err := filelock.Unlock(f)
+
+ if closeErr := f.Close(); err == nil {
+ err = closeErr
+ }
+ return err
+}
diff --git a/libgo/go/cmd/go/internal/lockedfile/lockedfile_plan9.go b/libgo/go/cmd/go/internal/lockedfile/lockedfile_plan9.go
new file mode 100644
index 00000000000..4a52c949763
--- /dev/null
+++ b/libgo/go/cmd/go/internal/lockedfile/lockedfile_plan9.go
@@ -0,0 +1,93 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build plan9
+
+package lockedfile
+
+import (
+ "math/rand"
+ "os"
+ "strings"
+ "time"
+)
+
+// Opening an exclusive-use file returns an error.
+// The expected error strings are:
+//
+// - "open/create -- file is locked" (cwfs, kfs)
+// - "exclusive lock" (fossil)
+// - "exclusive use file already open" (ramfs)
+var lockedErrStrings = [...]string{
+ "file is locked",
+ "exclusive lock",
+ "exclusive use file already open",
+}
+
+// Even though plan9 doesn't support the Lock/RLock/Unlock functions to
+// manipulate already-open files, IsLocked is still meaningful: os.OpenFile
+// itself may return errors that indicate that a file with the ModeExclusive bit
+// set is already open.
+func isLocked(err error) bool {
+ s := err.Error()
+
+ for _, frag := range lockedErrStrings {
+ if strings.Contains(s, frag) {
+ return true
+ }
+ }
+
+ return false
+}
+
+func openFile(name string, flag int, perm os.FileMode) (*os.File, error) {
+ // Plan 9 uses a mode bit instead of explicit lock/unlock syscalls.
+ //
+ // Per http://man.cat-v.org/plan_9/5/stat: “Exclusive use files may be open
+ // for I/O by only one fid at a time across all clients of the server. If a
+ // second open is attempted, it draws an error.”
+ //
+ // So we can try to open a locked file, but if it fails we're on our own to
+ // figure out when it becomes available. We'll use exponential backoff with
+ // some jitter and an arbitrary limit of 500ms.
+
+ // If the file was unpacked or created by some other program, it might not
+ // have the ModeExclusive bit set. Set it before we call OpenFile, so that we
+ // can be confident that a successful OpenFile implies exclusive use.
+ if fi, err := os.Stat(name); err == nil {
+ if fi.Mode()&os.ModeExclusive == 0 {
+ if err := os.Chmod(name, fi.Mode()|os.ModeExclusive); err != nil {
+ return nil, err
+ }
+ }
+ } else if !os.IsNotExist(err) {
+ return nil, err
+ }
+
+ nextSleep := 1 * time.Millisecond
+ const maxSleep = 500 * time.Millisecond
+ for {
+ f, err := os.OpenFile(name, flag, perm|os.ModeExclusive)
+ if err == nil {
+ return f, nil
+ }
+
+ if !isLocked(err) {
+ return nil, err
+ }
+
+ time.Sleep(nextSleep)
+
+ nextSleep += nextSleep
+ if nextSleep > maxSleep {
+ nextSleep = maxSleep
+ }
+ // Apply 10% jitter to avoid synchronizing collisions.
+ nextSleep += time.Duration((0.1*rand.Float64() - 0.05) * float64(nextSleep))
+ }
+}
+
+func closeFile(f *os.File) error {
+ return f.Close()
+}
diff --git a/libgo/go/cmd/go/internal/lockedfile/lockedfile_test.go b/libgo/go/cmd/go/internal/lockedfile/lockedfile_test.go
new file mode 100644
index 00000000000..6d5819efdb0
--- /dev/null
+++ b/libgo/go/cmd/go/internal/lockedfile/lockedfile_test.go
@@ -0,0 +1,174 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// js and nacl do not support inter-process file locking.
+// +build !js,!nacl
+
+package lockedfile_test
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "testing"
+ "time"
+
+ "cmd/go/internal/lockedfile"
+)
+
+func mustTempDir(t *testing.T) (dir string, remove func()) {
+ t.Helper()
+
+ dir, err := ioutil.TempDir("", filepath.Base(t.Name()))
+ if err != nil {
+ t.Fatal(err)
+ }
+ return dir, func() { os.RemoveAll(dir) }
+}
+
+const (
+ quiescent = 10 * time.Millisecond
+ probablyStillBlocked = 10 * time.Second
+)
+
+func mustBlock(t *testing.T, desc string, f func()) (wait func(*testing.T)) {
+ t.Helper()
+
+ done := make(chan struct{})
+ go func() {
+ f()
+ close(done)
+ }()
+
+ select {
+ case <-done:
+ t.Fatalf("%s unexpectedly did not block", desc)
+ return nil
+
+ case <-time.After(quiescent):
+ return func(t *testing.T) {
+ t.Helper()
+ select {
+ case <-time.After(probablyStillBlocked):
+ t.Fatalf("%s is unexpectedly still blocked after %v", desc, probablyStillBlocked)
+ case <-done:
+ }
+ }
+ }
+}
+
+func TestMutexExcludes(t *testing.T) {
+ t.Parallel()
+
+ dir, remove := mustTempDir(t)
+ defer remove()
+
+ path := filepath.Join(dir, "lock")
+
+ mu := lockedfile.MutexAt(path)
+ t.Logf("mu := MutexAt(_)")
+
+ unlock, err := mu.Lock()
+ if err != nil {
+ t.Fatalf("mu.Lock: %v", err)
+ }
+ t.Logf("unlock, _ := mu.Lock()")
+
+ mu2 := lockedfile.MutexAt(mu.Path)
+ t.Logf("mu2 := MutexAt(mu.Path)")
+
+ wait := mustBlock(t, "mu2.Lock()", func() {
+ unlock2, err := mu2.Lock()
+ if err != nil {
+ t.Errorf("mu2.Lock: %v", err)
+ return
+ }
+ t.Logf("unlock2, _ := mu2.Lock()")
+ t.Logf("unlock2()")
+ unlock2()
+ })
+
+ t.Logf("unlock()")
+ unlock()
+ wait(t)
+}
+
+func TestReadWaitsForLock(t *testing.T) {
+ t.Parallel()
+
+ dir, remove := mustTempDir(t)
+ defer remove()
+
+ path := filepath.Join(dir, "timestamp.txt")
+
+ f, err := lockedfile.Create(path)
+ if err != nil {
+ t.Fatalf("Create: %v", err)
+ }
+ defer f.Close()
+
+ const (
+ part1 = "part 1\n"
+ part2 = "part 2\n"
+ )
+ _, err = f.WriteString(part1)
+ if err != nil {
+ t.Fatalf("WriteString: %v", err)
+ }
+ t.Logf("WriteString(%q) = <nil>", part1)
+
+ wait := mustBlock(t, "Read", func() {
+ b, err := lockedfile.Read(path)
+ if err != nil {
+ t.Errorf("Read: %v", err)
+ return
+ }
+
+ const want = part1 + part2
+ got := string(b)
+ if got == want {
+ t.Logf("Read(_) = %q", got)
+ } else {
+ t.Errorf("Read(_) = %q, _; want %q", got, want)
+ }
+ })
+
+ _, err = f.WriteString(part2)
+ if err != nil {
+ t.Errorf("WriteString: %v", err)
+ } else {
+ t.Logf("WriteString(%q) = <nil>", part2)
+ }
+ f.Close()
+
+ wait(t)
+}
+
+func TestCanLockExistingFile(t *testing.T) {
+ t.Parallel()
+
+ dir, remove := mustTempDir(t)
+ defer remove()
+ path := filepath.Join(dir, "existing.txt")
+
+ if err := ioutil.WriteFile(path, []byte("ok"), 0777); err != nil {
+ t.Fatalf("ioutil.WriteFile: %v", err)
+ }
+
+ f, err := lockedfile.Edit(path)
+ if err != nil {
+ t.Fatalf("first Edit: %v", err)
+ }
+
+ wait := mustBlock(t, "Edit", func() {
+ other, err := lockedfile.Edit(path)
+ if err != nil {
+ t.Errorf("second Edit: %v", err)
+ }
+ other.Close()
+ })
+
+ f.Close()
+ wait(t)
+}
diff --git a/libgo/go/cmd/go/internal/lockedfile/mutex.go b/libgo/go/cmd/go/internal/lockedfile/mutex.go
new file mode 100644
index 00000000000..17f3751c371
--- /dev/null
+++ b/libgo/go/cmd/go/internal/lockedfile/mutex.go
@@ -0,0 +1,60 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package lockedfile
+
+import (
+ "fmt"
+ "os"
+)
+
+// A Mutex provides mutual exclusion within and across processes by locking a
+// well-known file. Such a file generally guards some other part of the
+// filesystem: for example, a Mutex file in a directory might guard access to
+// the entire tree rooted in that directory.
+//
+// Mutex does not implement sync.Locker: unlike a sync.Mutex, a lockedfile.Mutex
+// can fail to lock (e.g. if there is a permission error in the filesystem).
+//
+// Like a sync.Mutex, a Mutex may be included as a field of a larger struct but
+// must not be copied after first use. The Path field must be set before first
+// use and must not be change thereafter.
+type Mutex struct {
+ Path string // The path to the well-known lock file. Must be non-empty.
+}
+
+// MutexAt returns a new Mutex with Path set to the given non-empty path.
+func MutexAt(path string) *Mutex {
+ if path == "" {
+ panic("lockedfile.MutexAt: path must be non-empty")
+ }
+ return &Mutex{Path: path}
+}
+
+func (mu *Mutex) String() string {
+ return fmt.Sprintf("lockedfile.Mutex(%s)", mu.Path)
+}
+
+// Lock attempts to lock the Mutex.
+//
+// If successful, Lock returns a non-nil unlock function: it is provided as a
+// return-value instead of a separate method to remind the caller to check the
+// accompanying error. (See https://golang.org/issue/20803.)
+func (mu *Mutex) Lock() (unlock func(), err error) {
+ if mu.Path == "" {
+ panic("lockedfile.Mutex: missing Path during Lock")
+ }
+
+ // We could use either O_RDWR or O_WRONLY here. If we choose O_RDWR and the
+ // file at mu.Path is write-only, the call to OpenFile will fail with a
+ // permission error. That's actually what we want: if we add an RLock method
+ // in the future, it should call OpenFile with O_RDONLY and will require the
+ // files must be readable, so we should not let the caller make any
+ // assumptions about Mutex working with write-only files.
+ f, err := OpenFile(mu.Path, os.O_RDWR|os.O_CREATE, 0666)
+ if err != nil {
+ return nil, err
+ }
+ return func() { f.Close() }, nil
+}
diff --git a/libgo/go/cmd/go/internal/modcmd/download.go b/libgo/go/cmd/go/internal/modcmd/download.go
index cf42eff58a1..bbaba444f50 100644
--- a/libgo/go/cmd/go/internal/modcmd/download.go
+++ b/libgo/go/cmd/go/internal/modcmd/download.go
@@ -15,7 +15,7 @@ import (
)
var cmdDownload = &base.Command{
- UsageLine: "go mod download [-dir] [-json] [modules]",
+ UsageLine: "go mod download [-json] [modules]",
Short: "download modules to local cache",
Long: `
Download downloads the named modules, which can be module patterns selecting
@@ -128,6 +128,16 @@ func runDownload(cmd *base.Command, args []string) {
base.Fatalf("%v", err)
}
os.Stdout.Write(append(b, '\n'))
+ if m.Error != "" {
+ base.SetExitStatus(1)
+ }
+ }
+ } else {
+ for _, m := range mods {
+ if m.Error != "" {
+ base.Errorf("%s@%s: %s\n", m.Path, m.Version, m.Error)
+ }
}
+ base.ExitIfErrors()
}
}
diff --git a/libgo/go/cmd/go/internal/modcmd/edit.go b/libgo/go/cmd/go/internal/modcmd/edit.go
index 5fea3e48e08..5066e4ddf75 100644
--- a/libgo/go/cmd/go/internal/modcmd/edit.go
+++ b/libgo/go/cmd/go/internal/modcmd/edit.go
@@ -7,6 +7,7 @@
package modcmd
import (
+ "bytes"
"encoding/json"
"fmt"
"io/ioutil"
@@ -15,6 +16,7 @@ import (
"strings"
"cmd/go/internal/base"
+ "cmd/go/internal/modfetch"
"cmd/go/internal/modfile"
"cmd/go/internal/modload"
"cmd/go/internal/module"
@@ -62,6 +64,8 @@ The -require, -droprequire, -exclude, -dropexclude, -replace,
and -dropreplace editing flags may be repeated, and the changes
are applied in the order given.
+The -go=version flag sets the expected Go language version.
+
The -print flag prints the final go.mod in its text format instead of
writing it back to go.mod.
@@ -74,7 +78,8 @@ writing it back to go.mod. The JSON output corresponds to these Go types:
}
type GoMod struct {
- Module Module
+ Module Module
+ Go string
Require []Require
Exclude []Module
Replace []Replace
@@ -102,8 +107,8 @@ by invoking 'go mod edit' with -require, -exclude, and so on.
}
var (
- editFmt = cmdEdit.Flag.Bool("fmt", false, "")
- // editGo = cmdEdit.Flag.String("go", "", "")
+ editFmt = cmdEdit.Flag.Bool("fmt", false, "")
+ editGo = cmdEdit.Flag.String("go", "", "")
editJSON = cmdEdit.Flag.Bool("json", false, "")
editPrint = cmdEdit.Flag.Bool("print", false, "")
editModule = cmdEdit.Flag.String("module", "", "")
@@ -131,6 +136,7 @@ func init() {
func runEdit(cmd *base.Command, args []string) {
anyFlags :=
*editModule != "" ||
+ *editGo != "" ||
*editJSON ||
*editPrint ||
*editFmt ||
@@ -151,8 +157,7 @@ func runEdit(cmd *base.Command, args []string) {
if len(args) == 1 {
gomod = args[0]
} else {
- modload.MustInit()
- gomod = filepath.Join(modload.ModRoot, "go.mod")
+ gomod = filepath.Join(modload.ModRoot(), "go.mod")
}
if *editModule != "" {
@@ -161,7 +166,11 @@ func runEdit(cmd *base.Command, args []string) {
}
}
- // TODO(rsc): Implement -go= once we start advertising it.
+ if *editGo != "" {
+ if !modfile.GoVersionRE.MatchString(*editGo) {
+ base.Fatalf(`go mod: invalid -go option; expecting something like "-go 1.12"`)
+ }
+ }
data, err := ioutil.ReadFile(gomod)
if err != nil {
@@ -174,7 +183,13 @@ func runEdit(cmd *base.Command, args []string) {
}
if *editModule != "" {
- modFile.AddModuleStmt(modload.CmdModModule)
+ modFile.AddModuleStmt(*editModule)
+ }
+
+ if *editGo != "" {
+ if err := modFile.AddGoStmt(*editGo); err != nil {
+ base.Fatalf("go: internal error: %v", err)
+ }
}
if len(edits) > 0 {
@@ -190,17 +205,23 @@ func runEdit(cmd *base.Command, args []string) {
return
}
- data, err = modFile.Format()
+ out, err := modFile.Format()
if err != nil {
base.Fatalf("go: %v", err)
}
if *editPrint {
- os.Stdout.Write(data)
+ os.Stdout.Write(out)
return
}
- if err := ioutil.WriteFile(gomod, data, 0666); err != nil {
+ unlock := modfetch.SideLock()
+ defer unlock()
+ lockedData, err := ioutil.ReadFile(gomod)
+ if err == nil && !bytes.Equal(lockedData, data) {
+ base.Fatalf("go: go.mod changed during editing; not overwriting")
+ }
+ if err := ioutil.WriteFile(gomod, out, 0666); err != nil {
base.Fatalf("go: %v", err)
}
}
@@ -344,6 +365,7 @@ func flagDropReplace(arg string) {
// fileJSON is the -json output data structure.
type fileJSON struct {
Module module.Version
+ Go string `json:",omitempty"`
Require []requireJSON
Exclude []module.Version
Replace []replaceJSON
@@ -364,6 +386,9 @@ type replaceJSON struct {
func editPrintJSON(modFile *modfile.File) {
var f fileJSON
f.Module = modFile.Module.Mod
+ if modFile.Go != nil {
+ f.Go = modFile.Go.Version
+ }
for _, r := range modFile.Require {
f.Require = append(f.Require, requireJSON{Path: r.Mod.Path, Version: r.Mod.Version, Indirect: r.Indirect})
}
diff --git a/libgo/go/cmd/go/internal/modcmd/init.go b/libgo/go/cmd/go/internal/modcmd/init.go
index f510a46262b..0f7421e5849 100644
--- a/libgo/go/cmd/go/internal/modcmd/init.go
+++ b/libgo/go/cmd/go/internal/modcmd/init.go
@@ -10,6 +10,7 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/modload"
"os"
+ "strings"
)
var cmdInit = &base.Command{
@@ -37,5 +38,8 @@ func runInit(cmd *base.Command, args []string) {
if _, err := os.Stat("go.mod"); err == nil {
base.Fatalf("go mod init: go.mod already exists")
}
+ if strings.Contains(modload.CmdModModule, "@") {
+ base.Fatalf("go mod init: module path must not contain '@'")
+ }
modload.InitMod() // does all the hard work
}
diff --git a/libgo/go/cmd/go/internal/modcmd/tidy.go b/libgo/go/cmd/go/internal/modcmd/tidy.go
index f2063a9ea60..839c92a0a02 100644
--- a/libgo/go/cmd/go/internal/modcmd/tidy.go
+++ b/libgo/go/cmd/go/internal/modcmd/tidy.go
@@ -77,7 +77,17 @@ func modTidyGoSum() {
keep := make(map[module.Version]bool)
var walk func(module.Version)
walk = func(m module.Version) {
- keep[m] = true
+ // If we build using a replacement module, keep the sum for the replacement,
+ // since that's the code we'll actually use during a build.
+ //
+ // TODO(golang.org/issue/29182): Perhaps we should keep both sums, and the
+ // sums for both sets of transitive requirements.
+ r := modload.Replacement(m)
+ if r.Path == "" {
+ keep[m] = true
+ } else {
+ keep[r] = true
+ }
list, _ := reqs.Required(m)
for _, r := range list {
if !keep[r] {
diff --git a/libgo/go/cmd/go/internal/modcmd/vendor.go b/libgo/go/cmd/go/internal/modcmd/vendor.go
index 62e74585359..b70f25cec39 100644
--- a/libgo/go/cmd/go/internal/modcmd/vendor.go
+++ b/libgo/go/cmd/go/internal/modcmd/vendor.go
@@ -43,9 +43,9 @@ func runVendor(cmd *base.Command, args []string) {
}
pkgs := modload.LoadVendor()
- vdir := filepath.Join(modload.ModRoot, "vendor")
+ vdir := filepath.Join(modload.ModRoot(), "vendor")
if err := os.RemoveAll(vdir); err != nil {
- base.Fatalf("go vendor: %v", err)
+ base.Fatalf("go mod vendor: %v", err)
}
modpkgs := make(map[module.Version][]string)
@@ -85,7 +85,7 @@ func runVendor(cmd *base.Command, args []string) {
return
}
if err := ioutil.WriteFile(filepath.Join(vdir, "modules.txt"), buf.Bytes(), 0666); err != nil {
- base.Fatalf("go vendor: %v", err)
+ base.Fatalf("go mod vendor: %v", err)
}
}
@@ -172,10 +172,10 @@ func matchNonTest(info os.FileInfo) bool {
func copyDir(dst, src string, match func(os.FileInfo) bool) {
files, err := ioutil.ReadDir(src)
if err != nil {
- base.Fatalf("go vendor: %v", err)
+ base.Fatalf("go mod vendor: %v", err)
}
if err := os.MkdirAll(dst, 0777); err != nil {
- base.Fatalf("go vendor: %v", err)
+ base.Fatalf("go mod vendor: %v", err)
}
for _, file := range files {
if file.IsDir() || !file.Mode().IsRegular() || !match(file) {
@@ -183,18 +183,18 @@ func copyDir(dst, src string, match func(os.FileInfo) bool) {
}
r, err := os.Open(filepath.Join(src, file.Name()))
if err != nil {
- base.Fatalf("go vendor: %v", err)
+ base.Fatalf("go mod vendor: %v", err)
}
w, err := os.Create(filepath.Join(dst, file.Name()))
if err != nil {
- base.Fatalf("go vendor: %v", err)
+ base.Fatalf("go mod vendor: %v", err)
}
if _, err := io.Copy(w, r); err != nil {
- base.Fatalf("go vendor: %v", err)
+ base.Fatalf("go mod vendor: %v", err)
}
r.Close()
if err := w.Close(); err != nil {
- base.Fatalf("go vendor: %v", err)
+ base.Fatalf("go mod vendor: %v", err)
}
}
}
diff --git a/libgo/go/cmd/go/internal/modconv/convert_test.go b/libgo/go/cmd/go/internal/modconv/convert_test.go
index ad27abb8ef7..4d55d73f214 100644
--- a/libgo/go/cmd/go/internal/modconv/convert_test.go
+++ b/libgo/go/cmd/go/internal/modconv/convert_test.go
@@ -146,7 +146,7 @@ func TestConvertLegacyConfig(t *testing.T) {
}
for _, tt := range tests {
- t.Run(strings.Replace(tt.path, "/", "_", -1)+"_"+tt.vers, func(t *testing.T) {
+ t.Run(strings.ReplaceAll(tt.path, "/", "_")+"_"+tt.vers, func(t *testing.T) {
f, err := modfile.Parse("golden", []byte(tt.gomod), nil)
if err != nil {
t.Fatal(err)
diff --git a/libgo/go/cmd/go/internal/modfetch/cache.go b/libgo/go/cmd/go/internal/modfetch/cache.go
index 1f9cc96c3ec..1ccd43dc2ae 100644
--- a/libgo/go/cmd/go/internal/modfetch/cache.go
+++ b/libgo/go/cmd/go/internal/modfetch/cache.go
@@ -8,15 +8,18 @@ import (
"bytes"
"encoding/json"
"fmt"
+ "io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"cmd/go/internal/base"
+ "cmd/go/internal/lockedfile"
"cmd/go/internal/modfetch/codehost"
"cmd/go/internal/module"
"cmd/go/internal/par"
+ "cmd/go/internal/renameio"
"cmd/go/internal/semver"
)
@@ -53,6 +56,8 @@ func CachePath(m module.Version, suffix string) (string, error) {
return filepath.Join(dir, encVer+"."+suffix), nil
}
+// DownloadDir returns the directory to which m should be downloaded.
+// Note that the directory may not yet exist.
func DownloadDir(m module.Version) (string, error) {
if PkgMod == "" {
return "", fmt.Errorf("internal error: modfetch.PkgMod not set")
@@ -74,6 +79,37 @@ func DownloadDir(m module.Version) (string, error) {
return filepath.Join(PkgMod, enc+"@"+encVer), nil
}
+// lockVersion locks a file within the module cache that guards the downloading
+// and extraction of the zipfile for the given module version.
+func lockVersion(mod module.Version) (unlock func(), err error) {
+ path, err := CachePath(mod, "lock")
+ if err != nil {
+ return nil, err
+ }
+ if err := os.MkdirAll(filepath.Dir(path), 0777); err != nil {
+ return nil, err
+ }
+ return lockedfile.MutexAt(path).Lock()
+}
+
+// SideLock locks a file within the module cache that that guards edits to files
+// outside the cache, such as go.sum and go.mod files in the user's working
+// directory. It returns a function that must be called to unlock the file.
+func SideLock() (unlock func()) {
+ if PkgMod == "" {
+ base.Fatalf("go: internal error: modfetch.PkgMod not set")
+ }
+ path := filepath.Join(PkgMod, "cache", "lock")
+ if err := os.MkdirAll(filepath.Dir(path), 0777); err != nil {
+ base.Fatalf("go: failed to create cache directory %s: %v", filepath.Dir(path), err)
+ }
+ unlock, err := lockedfile.MutexAt(path).Lock()
+ if err != nil {
+ base.Fatalf("go: failed to lock file at %v", path)
+ }
+ return unlock
+}
+
// A cachingRepo is a cache around an underlying Repo,
// avoiding redundant calls to ModulePath, Versions, Stat, Latest, and GoMod (but not Zip).
// It is also safe for simultaneous use by multiple goroutines
@@ -129,16 +165,18 @@ func (r *cachingRepo) Stat(rev string) (*RevInfo, error) {
}
info, err = r.r.Stat(rev)
if err == nil {
- if err := writeDiskStat(file, info); err != nil {
- fmt.Fprintf(os.Stderr, "go: writing stat cache: %v\n", err)
- }
// If we resolved, say, 1234abcde to v0.0.0-20180604122334-1234abcdef78,
// then save the information under the proper version, for future use.
if info.Version != rev {
+ file, _ = CachePath(module.Version{Path: r.path, Version: info.Version}, "info")
r.cache.Do("stat:"+info.Version, func() interface{} {
return cachedInfo{info, err}
})
}
+
+ if err := writeDiskStat(file, info); err != nil {
+ fmt.Fprintf(os.Stderr, "go: writing stat cache: %v\n", err)
+ }
}
return cachedInfo{info, err}
}).(cachedInfo)
@@ -213,8 +251,8 @@ func (r *cachingRepo) GoMod(rev string) ([]byte, error) {
return append([]byte(nil), c.text...), nil
}
-func (r *cachingRepo) Zip(version, tmpdir string) (string, error) {
- return r.r.Zip(version, tmpdir)
+func (r *cachingRepo) Zip(dst io.Writer, version string) error {
+ return r.r.Zip(dst, version)
}
// Stat is like Lookup(path).Stat(rev) but avoids the
@@ -383,7 +421,7 @@ func readDiskStatByHash(path, rev string) (file string, info *RevInfo, err error
// and should ignore it.
var oldVgoPrefix = []byte("//vgo 0.0.")
-// readDiskGoMod reads a cached stat result from disk,
+// readDiskGoMod reads a cached go.mod file from disk,
// returning the name of the cache file and the result.
// If the read fails, the caller can use
// writeDiskGoMod(file, data) to write a new cache entry.
@@ -449,22 +487,8 @@ func writeDiskCache(file string, data []byte) error {
if err := os.MkdirAll(filepath.Dir(file), 0777); err != nil {
return err
}
- // Write data to temp file next to target file.
- f, err := ioutil.TempFile(filepath.Dir(file), filepath.Base(file)+".tmp-")
- if err != nil {
- return err
- }
- defer os.Remove(f.Name())
- defer f.Close()
- if _, err := f.Write(data); err != nil {
- return err
- }
- if err := f.Close(); err != nil {
- return err
- }
- // Rename temp file onto cache file,
- // so that the cache file is always a complete file.
- if err := os.Rename(f.Name(), file); err != nil {
+
+ if err := renameio.WriteFile(file, data); err != nil {
return err
}
@@ -481,8 +505,18 @@ func rewriteVersionList(dir string) {
base.Fatalf("go: internal error: misuse of rewriteVersionList")
}
- // TODO(rsc): We should do some kind of directory locking here,
- // to avoid lost updates.
+ listFile := filepath.Join(dir, "list")
+
+ // We use a separate lockfile here instead of locking listFile itself because
+ // we want to use Rename to write the file atomically. The list may be read by
+ // a GOPROXY HTTP server, and if we crash midway through a rewrite (or if the
+ // HTTP server ignores our locking and serves the file midway through a
+ // rewrite) it's better to serve a stale list than a truncated one.
+ unlock, err := lockedfile.MutexAt(listFile + ".lock").Lock()
+ if err != nil {
+ base.Fatalf("go: can't lock version list lockfile: %v", err)
+ }
+ defer unlock()
infos, err := ioutil.ReadDir(dir)
if err != nil {
@@ -511,12 +545,12 @@ func rewriteVersionList(dir string) {
buf.WriteString(v)
buf.WriteString("\n")
}
- listFile := filepath.Join(dir, "list")
old, _ := ioutil.ReadFile(listFile)
if bytes.Equal(buf.Bytes(), old) {
return
}
- // TODO: Use rename to install file,
- // so that readers never see an incomplete file.
- ioutil.WriteFile(listFile, buf.Bytes(), 0666)
+
+ if err := renameio.WriteFile(listFile, buf.Bytes()); err != nil {
+ base.Fatalf("go: failed to write version list: %v", err)
+ }
}
diff --git a/libgo/go/cmd/go/internal/modfetch/codehost/codehost.go b/libgo/go/cmd/go/internal/modfetch/codehost/codehost.go
index 4103ddc717f..6c17f7886f1 100644
--- a/libgo/go/cmd/go/internal/modfetch/codehost/codehost.go
+++ b/libgo/go/cmd/go/internal/modfetch/codehost/codehost.go
@@ -20,6 +20,7 @@ import (
"time"
"cmd/go/internal/cfg"
+ "cmd/go/internal/lockedfile"
"cmd/go/internal/str"
)
@@ -131,9 +132,9 @@ var WorkRoot string
// WorkDir returns the name of the cached work directory to use for the
// given repository type and name.
-func WorkDir(typ, name string) (string, error) {
+func WorkDir(typ, name string) (dir, lockfile string, err error) {
if WorkRoot == "" {
- return "", fmt.Errorf("codehost.WorkRoot not set")
+ return "", "", fmt.Errorf("codehost.WorkRoot not set")
}
// We name the work directory for the SHA256 hash of the type and name.
@@ -142,22 +143,41 @@ func WorkDir(typ, name string) (string, error) {
// that one checkout is never nested inside another. That nesting has
// led to security problems in the past.
if strings.Contains(typ, ":") {
- return "", fmt.Errorf("codehost.WorkDir: type cannot contain colon")
+ return "", "", fmt.Errorf("codehost.WorkDir: type cannot contain colon")
}
key := typ + ":" + name
- dir := filepath.Join(WorkRoot, fmt.Sprintf("%x", sha256.Sum256([]byte(key))))
+ dir = filepath.Join(WorkRoot, fmt.Sprintf("%x", sha256.Sum256([]byte(key))))
+
+ if cfg.BuildX {
+ fmt.Fprintf(os.Stderr, "mkdir -p %s # %s %s\n", filepath.Dir(dir), typ, name)
+ }
+ if err := os.MkdirAll(filepath.Dir(dir), 0777); err != nil {
+ return "", "", err
+ }
+
+ lockfile = dir + ".lock"
+ if cfg.BuildX {
+ fmt.Fprintf(os.Stderr, "# lock %s", lockfile)
+ }
+
+ unlock, err := lockedfile.MutexAt(lockfile).Lock()
+ if err != nil {
+ return "", "", fmt.Errorf("codehost.WorkDir: can't find or create lock file: %v", err)
+ }
+ defer unlock()
+
data, err := ioutil.ReadFile(dir + ".info")
info, err2 := os.Stat(dir)
if err == nil && err2 == nil && info.IsDir() {
// Info file and directory both already exist: reuse.
have := strings.TrimSuffix(string(data), "\n")
if have != key {
- return "", fmt.Errorf("%s exists with wrong content (have %q want %q)", dir+".info", have, key)
+ return "", "", fmt.Errorf("%s exists with wrong content (have %q want %q)", dir+".info", have, key)
}
if cfg.BuildX {
fmt.Fprintf(os.Stderr, "# %s for %s %s\n", dir, typ, name)
}
- return dir, nil
+ return dir, lockfile, nil
}
// Info file or directory missing. Start from scratch.
@@ -166,26 +186,30 @@ func WorkDir(typ, name string) (string, error) {
}
os.RemoveAll(dir)
if err := os.MkdirAll(dir, 0777); err != nil {
- return "", err
+ return "", "", err
}
if err := ioutil.WriteFile(dir+".info", []byte(key), 0666); err != nil {
os.RemoveAll(dir)
- return "", err
+ return "", "", err
}
- return dir, nil
+ return dir, lockfile, nil
}
type RunError struct {
- Cmd string
- Err error
- Stderr []byte
+ Cmd string
+ Err error
+ Stderr []byte
+ HelpText string
}
func (e *RunError) Error() string {
text := e.Cmd + ": " + e.Err.Error()
stderr := bytes.TrimRight(e.Stderr, "\n")
if len(stderr) > 0 {
- text += ":\n\t" + strings.Replace(string(stderr), "\n", "\n\t", -1)
+ text += ":\n\t" + strings.ReplaceAll(string(stderr), "\n", "\n\t")
+ }
+ if len(e.HelpText) > 0 {
+ text += "\n" + e.HelpText
}
return text
}
diff --git a/libgo/go/cmd/go/internal/modfetch/codehost/git.go b/libgo/go/cmd/go/internal/modfetch/codehost/git.go
index 87940a8f02c..588e7496cc5 100644
--- a/libgo/go/cmd/go/internal/modfetch/codehost/git.go
+++ b/libgo/go/cmd/go/internal/modfetch/codehost/git.go
@@ -17,6 +17,7 @@ import (
"sync"
"time"
+ "cmd/go/internal/lockedfile"
"cmd/go/internal/par"
)
@@ -57,22 +58,29 @@ func newGitRepo(remote string, localOK bool) (Repo, error) {
r := &gitRepo{remote: remote}
if strings.Contains(remote, "://") {
// This is a remote path.
- dir, err := WorkDir(gitWorkDirType, r.remote)
+ var err error
+ r.dir, r.mu.Path, err = WorkDir(gitWorkDirType, r.remote)
if err != nil {
return nil, err
}
- r.dir = dir
- if _, err := os.Stat(filepath.Join(dir, "objects")); err != nil {
- if _, err := Run(dir, "git", "init", "--bare"); err != nil {
- os.RemoveAll(dir)
+
+ unlock, err := r.mu.Lock()
+ if err != nil {
+ return nil, err
+ }
+ defer unlock()
+
+ if _, err := os.Stat(filepath.Join(r.dir, "objects")); err != nil {
+ if _, err := Run(r.dir, "git", "init", "--bare"); err != nil {
+ os.RemoveAll(r.dir)
return nil, err
}
// We could just say git fetch https://whatever later,
// but this lets us say git fetch origin instead, which
// is a little nicer. More importantly, using a named remote
// avoids a problem with Git LFS. See golang.org/issue/25605.
- if _, err := Run(dir, "git", "remote", "add", "origin", r.remote); err != nil {
- os.RemoveAll(dir)
+ if _, err := Run(r.dir, "git", "remote", "add", "origin", r.remote); err != nil {
+ os.RemoveAll(r.dir)
return nil, err
}
r.remote = "origin"
@@ -97,6 +105,7 @@ func newGitRepo(remote string, localOK bool) (Repo, error) {
return nil, fmt.Errorf("%s exists but is not a directory", remote)
}
r.dir = remote
+ r.mu.Path = r.dir + ".lock"
}
return r, nil
}
@@ -106,7 +115,8 @@ type gitRepo struct {
local bool
dir string
- mu sync.Mutex // protects fetchLevel, some git repo state
+ mu lockedfile.Mutex // protects fetchLevel and git repo state
+
fetchLevel int
statCache par.Cache
@@ -154,6 +164,11 @@ func (r *gitRepo) loadRefs() {
// Most of the time we only care about tags but sometimes we care about heads too.
out, err := Run(r.dir, "git", "ls-remote", "-q", r.remote)
if err != nil {
+ if rerr, ok := err.(*RunError); ok {
+ if bytes.Contains(rerr.Stderr, []byte("fatal: could not read Username")) {
+ rerr.HelpText = "If this is a private repository, see https://golang.org/doc/faq#git_https for additional information."
+ }
+ }
r.refsErr = err
return
}
@@ -304,11 +319,11 @@ func (r *gitRepo) stat(rev string) (*RevInfo, error) {
}
// Protect r.fetchLevel and the "fetch more and more" sequence.
- // TODO(rsc): Add LockDir and use it for protecting that
- // sequence, so that multiple processes don't collide in their
- // git commands.
- r.mu.Lock()
- defer r.mu.Unlock()
+ unlock, err := r.mu.Lock()
+ if err != nil {
+ return nil, err
+ }
+ defer unlock()
// Perhaps r.localTags did not have the ref when we loaded local tags,
// but we've since done fetches that pulled down the hash we need
@@ -495,8 +510,11 @@ func (r *gitRepo) ReadFileRevs(revs []string, file string, maxSize int64) (map[s
// Protect r.fetchLevel and the "fetch more and more" sequence.
// See stat method above.
- r.mu.Lock()
- defer r.mu.Unlock()
+ unlock, err := r.mu.Lock()
+ if err != nil {
+ return nil, err
+ }
+ defer unlock()
var refs []string
var protoFlag []string
@@ -658,8 +676,11 @@ func (r *gitRepo) RecentTag(rev, prefix string) (tag string, err error) {
// There are plausible tags, but we don't know if rev is a descendent of any of them.
// Fetch the history to find out.
- r.mu.Lock()
- defer r.mu.Unlock()
+ unlock, err := r.mu.Lock()
+ if err != nil {
+ return "", err
+ }
+ defer unlock()
if r.fetchLevel < fetchAll {
// Fetch all heads and tags and see if that gives us enough history.
@@ -678,7 +699,7 @@ func (r *gitRepo) RecentTag(rev, prefix string) (tag string, err error) {
// unreachable for a reason).
//
// Try one last time in case some other goroutine fetched rev while we were
- // waiting on r.mu.
+ // waiting on the lock.
describe()
return tag, err
}
@@ -694,6 +715,16 @@ func (r *gitRepo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser,
return nil, "", err
}
+ unlock, err := r.mu.Lock()
+ if err != nil {
+ return nil, "", err
+ }
+ defer unlock()
+
+ if err := ensureGitAttributes(r.dir); err != nil {
+ return nil, "", err
+ }
+
// Incredibly, git produces different archives depending on whether
// it is running on a Windows system or not, in an attempt to normalize
// text file line endings. Setting -c core.autocrlf=input means only
@@ -709,3 +740,43 @@ func (r *gitRepo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser,
return ioutil.NopCloser(bytes.NewReader(archive)), "", nil
}
+
+// ensureGitAttributes makes sure export-subst and export-ignore features are
+// disabled for this repo. This is intended to be run prior to running git
+// archive so that zip files are generated that produce consistent ziphashes
+// for a given revision, independent of variables such as git version and the
+// size of the repo.
+//
+// See: https://github.com/golang/go/issues/27153
+func ensureGitAttributes(repoDir string) (err error) {
+ const attr = "\n* -export-subst -export-ignore\n"
+
+ d := repoDir + "/info"
+ p := d + "/attributes"
+
+ if err := os.MkdirAll(d, 0755); err != nil {
+ return err
+ }
+
+ f, err := os.OpenFile(p, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ closeErr := f.Close()
+ if closeErr != nil {
+ err = closeErr
+ }
+ }()
+
+ b, err := ioutil.ReadAll(f)
+ if err != nil {
+ return err
+ }
+ if !bytes.HasSuffix(b, []byte(attr)) {
+ _, err := f.WriteString(attr)
+ return err
+ }
+
+ return nil
+}
diff --git a/libgo/go/cmd/go/internal/modfetch/codehost/vcs.go b/libgo/go/cmd/go/internal/modfetch/codehost/vcs.go
index 9e862a0ef8c..59c2b15d19a 100644
--- a/libgo/go/cmd/go/internal/modfetch/codehost/vcs.go
+++ b/libgo/go/cmd/go/internal/modfetch/codehost/vcs.go
@@ -18,6 +18,7 @@ import (
"sync"
"time"
+ "cmd/go/internal/lockedfile"
"cmd/go/internal/par"
"cmd/go/internal/str"
)
@@ -27,12 +28,19 @@ import (
// to get the code, but we can't access it due to the error.
// The caller should report this error instead of continuing to probe
// other possible module paths.
+//
+// TODO(bcmills): See if we can invert this. (Return a distinguished error for
+// “repo not found” and treat everything else as terminal.)
type VCSError struct {
Err error
}
func (e *VCSError) Error() string { return e.Err.Error() }
+func vcsErrorf(format string, a ...interface{}) error {
+ return &VCSError{Err: fmt.Errorf(format, a...)}
+}
+
func NewRepo(vcs, remote string) (Repo, error) {
type key struct {
vcs string
@@ -56,6 +64,8 @@ func NewRepo(vcs, remote string) (Repo, error) {
var vcsRepoCache par.Cache
type vcsRepo struct {
+ mu lockedfile.Mutex // protects all commands, so we don't have to decide which are safe on a per-VCS basis
+
remote string
cmd *vcsCmd
dir string
@@ -81,18 +91,27 @@ func newVCSRepo(vcs, remote string) (Repo, error) {
if !strings.Contains(remote, "://") {
return nil, fmt.Errorf("invalid vcs remote: %s %s", vcs, remote)
}
+
r := &vcsRepo{remote: remote, cmd: cmd}
+ var err error
+ r.dir, r.mu.Path, err = WorkDir(vcsWorkDirType+vcs, r.remote)
+ if err != nil {
+ return nil, err
+ }
+
if cmd.init == nil {
return r, nil
}
- dir, err := WorkDir(vcsWorkDirType+vcs, r.remote)
+
+ unlock, err := r.mu.Lock()
if err != nil {
return nil, err
}
- r.dir = dir
- if _, err := os.Stat(filepath.Join(dir, "."+vcs)); err != nil {
- if _, err := Run(dir, cmd.init(r.remote)); err != nil {
- os.RemoveAll(dir)
+ defer unlock()
+
+ if _, err := os.Stat(filepath.Join(r.dir, "."+vcs)); err != nil {
+ if _, err := Run(r.dir, cmd.init(r.remote)); err != nil {
+ os.RemoveAll(r.dir)
return nil, err
}
}
@@ -270,6 +289,12 @@ func (r *vcsRepo) loadBranches() {
}
func (r *vcsRepo) Tags(prefix string) ([]string, error) {
+ unlock, err := r.mu.Lock()
+ if err != nil {
+ return nil, err
+ }
+ defer unlock()
+
r.tagsOnce.Do(r.loadTags)
tags := []string{}
@@ -283,6 +308,12 @@ func (r *vcsRepo) Tags(prefix string) ([]string, error) {
}
func (r *vcsRepo) Stat(rev string) (*RevInfo, error) {
+ unlock, err := r.mu.Lock()
+ if err != nil {
+ return nil, err
+ }
+ defer unlock()
+
if rev == "latest" {
rev = r.cmd.latest
}
@@ -315,7 +346,7 @@ func (r *vcsRepo) fetch() {
func (r *vcsRepo) statLocal(rev string) (*RevInfo, error) {
out, err := Run(r.dir, r.cmd.statLocal(rev, r.remote))
if err != nil {
- return nil, fmt.Errorf("unknown revision %s", rev)
+ return nil, vcsErrorf("unknown revision %s", rev)
}
return r.cmd.parseStat(rev, string(out))
}
@@ -332,6 +363,14 @@ func (r *vcsRepo) ReadFile(rev, file string, maxSize int64) ([]byte, error) {
if err != nil {
return nil, err
}
+
+ // r.Stat acquires r.mu, so lock after that.
+ unlock, err := r.mu.Lock()
+ if err != nil {
+ return nil, err
+ }
+ defer unlock()
+
out, err := Run(r.dir, r.cmd.readFile(rev, file, r.remote))
if err != nil {
return nil, os.ErrNotExist
@@ -340,14 +379,42 @@ func (r *vcsRepo) ReadFile(rev, file string, maxSize int64) ([]byte, error) {
}
func (r *vcsRepo) ReadFileRevs(revs []string, file string, maxSize int64) (map[string]*FileRev, error) {
- return nil, fmt.Errorf("ReadFileRevs not implemented")
+ // We don't technically need to lock here since we're returning an error
+ // uncondititonally, but doing so anyway will help to avoid baking in
+ // lock-inversion bugs.
+ unlock, err := r.mu.Lock()
+ if err != nil {
+ return nil, err
+ }
+ defer unlock()
+
+ return nil, vcsErrorf("ReadFileRevs not implemented")
}
func (r *vcsRepo) RecentTag(rev, prefix string) (tag string, err error) {
- return "", fmt.Errorf("RecentTags not implemented")
+ // We don't technically need to lock here since we're returning an error
+ // uncondititonally, but doing so anyway will help to avoid baking in
+ // lock-inversion bugs.
+ unlock, err := r.mu.Lock()
+ if err != nil {
+ return "", err
+ }
+ defer unlock()
+
+ return "", vcsErrorf("RecentTag not implemented")
}
func (r *vcsRepo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser, actualSubdir string, err error) {
+ if r.cmd.readZip == nil {
+ return nil, "", vcsErrorf("ReadZip not implemented for %s", r.cmd.vcs)
+ }
+
+ unlock, err := r.mu.Lock()
+ if err != nil {
+ return nil, "", err
+ }
+ defer unlock()
+
if rev == "latest" {
rev = r.cmd.latest
}
@@ -392,7 +459,7 @@ func (d *deleteCloser) Close() error {
func hgParseStat(rev, out string) (*RevInfo, error) {
f := strings.Fields(string(out))
if len(f) < 3 {
- return nil, fmt.Errorf("unexpected response from hg log: %q", out)
+ return nil, vcsErrorf("unexpected response from hg log: %q", out)
}
hash := f[0]
version := rev
@@ -401,7 +468,7 @@ func hgParseStat(rev, out string) (*RevInfo, error) {
}
t, err := strconv.ParseInt(f[1], 10, 64)
if err != nil {
- return nil, fmt.Errorf("invalid time from hg log: %q", out)
+ return nil, vcsErrorf("invalid time from hg log: %q", out)
}
var tags []string
@@ -430,12 +497,12 @@ func svnParseStat(rev, out string) (*RevInfo, error) {
} `xml:"logentry"`
}
if err := xml.Unmarshal([]byte(out), &log); err != nil {
- return nil, fmt.Errorf("unexpected response from svn log --xml: %v\n%s", err, out)
+ return nil, vcsErrorf("unexpected response from svn log --xml: %v\n%s", err, out)
}
t, err := time.Parse(time.RFC3339, log.Logentry.Date)
if err != nil {
- return nil, fmt.Errorf("unexpected response from svn log --xml: %v\n%s", err, out)
+ return nil, vcsErrorf("unexpected response from svn log --xml: %v\n%s", err, out)
}
info := &RevInfo{
@@ -471,23 +538,23 @@ func bzrParseStat(rev, out string) (*RevInfo, error) {
}
i, err := strconv.ParseInt(val, 10, 64)
if err != nil {
- return nil, fmt.Errorf("unexpected revno from bzr log: %q", line)
+ return nil, vcsErrorf("unexpected revno from bzr log: %q", line)
}
revno = i
case "timestamp":
j := strings.Index(val, " ")
if j < 0 {
- return nil, fmt.Errorf("unexpected timestamp from bzr log: %q", line)
+ return nil, vcsErrorf("unexpected timestamp from bzr log: %q", line)
}
t, err := time.Parse("2006-01-02 15:04:05 -0700", val[j+1:])
if err != nil {
- return nil, fmt.Errorf("unexpected timestamp from bzr log: %q", line)
+ return nil, vcsErrorf("unexpected timestamp from bzr log: %q", line)
}
tm = t.UTC()
}
}
if revno == 0 || tm.IsZero() {
- return nil, fmt.Errorf("unexpected response from bzr log: %q", out)
+ return nil, vcsErrorf("unexpected response from bzr log: %q", out)
}
info := &RevInfo{
@@ -504,11 +571,11 @@ func fossilParseStat(rev, out string) (*RevInfo, error) {
if strings.HasPrefix(line, "uuid:") {
f := strings.Fields(line)
if len(f) != 5 || len(f[1]) != 40 || f[4] != "UTC" {
- return nil, fmt.Errorf("unexpected response from fossil info: %q", line)
+ return nil, vcsErrorf("unexpected response from fossil info: %q", line)
}
t, err := time.Parse("2006-01-02 15:04:05", f[2]+" "+f[3])
if err != nil {
- return nil, fmt.Errorf("unexpected response from fossil info: %q", line)
+ return nil, vcsErrorf("unexpected response from fossil info: %q", line)
}
hash := f[1]
version := rev
@@ -524,5 +591,5 @@ func fossilParseStat(rev, out string) (*RevInfo, error) {
return info, nil
}
}
- return nil, fmt.Errorf("unexpected response from fossil info: %q", out)
+ return nil, vcsErrorf("unexpected response from fossil info: %q", out)
}
diff --git a/libgo/go/cmd/go/internal/modfetch/coderepo.go b/libgo/go/cmd/go/internal/modfetch/coderepo.go
index 9cf0e911508..5018b6d8af7 100644
--- a/libgo/go/cmd/go/internal/modfetch/coderepo.go
+++ b/libgo/go/cmd/go/internal/modfetch/coderepo.go
@@ -407,25 +407,26 @@ func (r *codeRepo) modPrefix(rev string) string {
return r.modPath + "@" + rev
}
-func (r *codeRepo) Zip(version string, tmpdir string) (tmpfile string, err error) {
+func (r *codeRepo) Zip(dst io.Writer, version string) error {
rev, dir, _, err := r.findDir(version)
if err != nil {
- return "", err
+ return err
}
dl, actualDir, err := r.code.ReadZip(rev, dir, codehost.MaxZipFile)
if err != nil {
- return "", err
+ return err
}
+ defer dl.Close()
if actualDir != "" && !hasPathPrefix(dir, actualDir) {
- return "", fmt.Errorf("internal error: downloading %v %v: dir=%q but actualDir=%q", r.path, rev, dir, actualDir)
+ return fmt.Errorf("internal error: downloading %v %v: dir=%q but actualDir=%q", r.path, rev, dir, actualDir)
}
subdir := strings.Trim(strings.TrimPrefix(dir, actualDir), "/")
// Spool to local file.
- f, err := ioutil.TempFile(tmpdir, "go-codehost-")
+ f, err := ioutil.TempFile("", "go-codehost-")
if err != nil {
dl.Close()
- return "", err
+ return err
}
defer os.Remove(f.Name())
defer f.Close()
@@ -433,35 +434,24 @@ func (r *codeRepo) Zip(version string, tmpdir string) (tmpfile string, err error
lr := &io.LimitedReader{R: dl, N: maxSize + 1}
if _, err := io.Copy(f, lr); err != nil {
dl.Close()
- return "", err
+ return err
}
dl.Close()
if lr.N <= 0 {
- return "", fmt.Errorf("downloaded zip file too large")
+ return fmt.Errorf("downloaded zip file too large")
}
size := (maxSize + 1) - lr.N
if _, err := f.Seek(0, 0); err != nil {
- return "", err
+ return err
}
// Translate from zip file we have to zip file we want.
zr, err := zip.NewReader(f, size)
if err != nil {
- return "", err
- }
- f2, err := ioutil.TempFile(tmpdir, "go-codezip-")
- if err != nil {
- return "", err
+ return err
}
- zw := zip.NewWriter(f2)
- newName := f2.Name()
- defer func() {
- f2.Close()
- if err != nil {
- os.Remove(newName)
- }
- }()
+ zw := zip.NewWriter(dst)
if subdir != "" {
subdir += "/"
}
@@ -472,12 +462,12 @@ func (r *codeRepo) Zip(version string, tmpdir string) (tmpfile string, err error
if topPrefix == "" {
i := strings.Index(zf.Name, "/")
if i < 0 {
- return "", fmt.Errorf("missing top-level directory prefix")
+ return fmt.Errorf("missing top-level directory prefix")
}
topPrefix = zf.Name[:i+1]
}
if !strings.HasPrefix(zf.Name, topPrefix) {
- return "", fmt.Errorf("zip file contains more than one top-level directory")
+ return fmt.Errorf("zip file contains more than one top-level directory")
}
dir, file := path.Split(zf.Name)
if file == "go.mod" {
@@ -497,11 +487,17 @@ func (r *codeRepo) Zip(version string, tmpdir string) (tmpfile string, err error
name = dir[:len(dir)-1]
}
}
+
for _, zf := range zr.File {
+ if !zf.FileInfo().Mode().IsRegular() {
+ // Skip symlinks (golang.org/issue/27093).
+ continue
+ }
+
if topPrefix == "" {
i := strings.Index(zf.Name, "/")
if i < 0 {
- return "", fmt.Errorf("missing top-level directory prefix")
+ return fmt.Errorf("missing top-level directory prefix")
}
topPrefix = zf.Name[:i+1]
}
@@ -509,7 +505,7 @@ func (r *codeRepo) Zip(version string, tmpdir string) (tmpfile string, err error
continue
}
if !strings.HasPrefix(zf.Name, topPrefix) {
- return "", fmt.Errorf("zip file contains more than one top-level directory")
+ return fmt.Errorf("zip file contains more than one top-level directory")
}
name := strings.TrimPrefix(zf.Name, topPrefix)
if !strings.HasPrefix(name, subdir) {
@@ -529,28 +525,28 @@ func (r *codeRepo) Zip(version string, tmpdir string) (tmpfile string, err error
}
base := path.Base(name)
if strings.ToLower(base) == "go.mod" && base != "go.mod" {
- return "", fmt.Errorf("zip file contains %s, want all lower-case go.mod", zf.Name)
+ return fmt.Errorf("zip file contains %s, want all lower-case go.mod", zf.Name)
}
if name == "LICENSE" {
haveLICENSE = true
}
- size := int64(zf.UncompressedSize)
+ size := int64(zf.UncompressedSize64)
if size < 0 || maxSize < size {
- return "", fmt.Errorf("module source tree too big")
+ return fmt.Errorf("module source tree too big")
}
maxSize -= size
rc, err := zf.Open()
if err != nil {
- return "", err
+ return err
}
w, err := zw.Create(r.modPrefix(version) + "/" + name)
lr := &io.LimitedReader{R: rc, N: size + 1}
if _, err := io.Copy(w, lr); err != nil {
- return "", err
+ return err
}
if lr.N <= 0 {
- return "", fmt.Errorf("individual file too large")
+ return fmt.Errorf("individual file too large")
}
}
@@ -559,21 +555,15 @@ func (r *codeRepo) Zip(version string, tmpdir string) (tmpfile string, err error
if err == nil {
w, err := zw.Create(r.modPrefix(version) + "/LICENSE")
if err != nil {
- return "", err
+ return err
}
if _, err := w.Write(data); err != nil {
- return "", err
+ return err
}
}
}
- if err := zw.Close(); err != nil {
- return "", err
- }
- if err := f2.Close(); err != nil {
- return "", err
- }
- return f2.Name(), nil
+ return zw.Close()
}
// hasPathPrefix reports whether the path s begins with the
diff --git a/libgo/go/cmd/go/internal/modfetch/coderepo_test.go b/libgo/go/cmd/go/internal/modfetch/coderepo_test.go
index 79b82786cb9..c93d8dbe442 100644
--- a/libgo/go/cmd/go/internal/modfetch/coderepo_test.go
+++ b/libgo/go/cmd/go/internal/modfetch/coderepo_test.go
@@ -284,10 +284,10 @@ var codeRepoTests = []struct {
{
path: "gopkg.in/yaml.v2",
rev: "v2",
- version: "v2.2.1",
- name: "5420a8b6744d3b0345ab293f6fcba19c978f1183",
- short: "5420a8b6744d",
- time: time.Date(2018, 3, 28, 19, 50, 20, 0, time.UTC),
+ version: "v2.2.2",
+ name: "51d6538a90f86fe93ac480b35f37b2be17fef232",
+ short: "51d6538a90f8",
+ time: time.Date(2018, 11, 15, 11, 05, 04, 0, time.UTC),
gomod: "module \"gopkg.in/yaml.v2\"\n\nrequire (\n\t\"gopkg.in/check.v1\" v0.0.0-20161208181325-20d25e280405\n)\n",
},
{
@@ -391,7 +391,13 @@ func TestCodeRepo(t *testing.T) {
}
}
if tt.zip != nil || tt.ziperr != "" {
- zipfile, err := repo.Zip(tt.version, tmpdir)
+ f, err := ioutil.TempFile(tmpdir, tt.version+".zip.")
+ if err != nil {
+ t.Fatalf("ioutil.TempFile: %v", err)
+ }
+ zipfile := f.Name()
+ err = repo.Zip(f, tt.version)
+ f.Close()
if err != nil {
if tt.ziperr != "" {
if err.Error() == tt.ziperr {
@@ -423,7 +429,7 @@ func TestCodeRepo(t *testing.T) {
}
}
}
- t.Run(strings.Replace(tt.path, "/", "_", -1)+"/"+tt.rev, f)
+ t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.rev, f)
if strings.HasPrefix(tt.path, vgotest1git) {
for _, alt := range altVgotests {
// Note: Communicating with f through tt; should be cleaned up.
@@ -442,7 +448,7 @@ func TestCodeRepo(t *testing.T) {
tt.rev = remap(tt.rev, m)
tt.gomoderr = remap(tt.gomoderr, m)
tt.ziperr = remap(tt.ziperr, m)
- t.Run(strings.Replace(tt.path, "/", "_", -1)+"/"+tt.rev, f)
+ t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.rev, f)
tt = old
}
}
@@ -473,9 +479,9 @@ func remap(name string, m map[string]string) string {
}
}
for k, v := range m {
- name = strings.Replace(name, k, v, -1)
+ name = strings.ReplaceAll(name, k, v)
if codehost.AllHex(k) {
- name = strings.Replace(name, k[:12], v[:12], -1)
+ name = strings.ReplaceAll(name, k[:12], v[:12])
}
}
return name
@@ -505,11 +511,11 @@ var codeRepoVersionsTests = []struct {
},
{
path: "gopkg.in/russross/blackfriday.v2",
- versions: []string{"v2.0.0"},
+ versions: []string{"v2.0.0", "v2.0.1"},
},
{
path: "gopkg.in/natefinch/lumberjack.v2",
- versions: nil,
+ versions: []string{"v2.0.0"},
},
}
@@ -522,7 +528,7 @@ func TestCodeRepoVersions(t *testing.T) {
}
defer os.RemoveAll(tmpdir)
for _, tt := range codeRepoVersionsTests {
- t.Run(strings.Replace(tt.path, "/", "_", -1), func(t *testing.T) {
+ t.Run(strings.ReplaceAll(tt.path, "/", "_"), func(t *testing.T) {
repo, err := Lookup(tt.path)
if err != nil {
t.Fatalf("Lookup(%q): %v", tt.path, err)
@@ -570,7 +576,7 @@ func TestLatest(t *testing.T) {
}
defer os.RemoveAll(tmpdir)
for _, tt := range latestTests {
- name := strings.Replace(tt.path, "/", "_", -1)
+ name := strings.ReplaceAll(tt.path, "/", "_")
t.Run(name, func(t *testing.T) {
repo, err := Lookup(tt.path)
if err != nil {
diff --git a/libgo/go/cmd/go/internal/modfetch/fetch.go b/libgo/go/cmd/go/internal/modfetch/fetch.go
index 2e26bac434d..81a6c843abc 100644
--- a/libgo/go/cmd/go/internal/modfetch/fetch.go
+++ b/libgo/go/cmd/go/internal/modfetch/fetch.go
@@ -21,6 +21,7 @@ import (
"cmd/go/internal/dirhash"
"cmd/go/internal/module"
"cmd/go/internal/par"
+ "cmd/go/internal/renameio"
)
var downloadCache par.Cache
@@ -34,9 +35,7 @@ func Download(mod module.Version) (dir string, err error) {
return "", fmt.Errorf("missing modfetch.PkgMod")
}
- // The par.Cache here avoids duplicate work but also
- // avoids conflicts from simultaneous calls by multiple goroutines
- // for the same version.
+ // The par.Cache here avoids duplicate work.
type cached struct {
dir string
err error
@@ -46,16 +45,8 @@ func Download(mod module.Version) (dir string, err error) {
if err != nil {
return cached{"", err}
}
- if files, _ := ioutil.ReadDir(dir); len(files) == 0 {
- zipfile, err := DownloadZip(mod)
- if err != nil {
- return cached{"", err}
- }
- modpath := mod.Path + "@" + mod.Version
- if err := Unzip(dir, zipfile, modpath, 0); err != nil {
- fmt.Fprintf(os.Stderr, "-> %s\n", err)
- return cached{"", err}
- }
+ if err := download(mod, dir); err != nil {
+ return cached{"", err}
}
checkSum(mod)
return cached{dir, nil}
@@ -63,14 +54,88 @@ func Download(mod module.Version) (dir string, err error) {
return c.dir, c.err
}
+func download(mod module.Version, dir string) (err error) {
+ // If the directory exists, the module has already been extracted.
+ fi, err := os.Stat(dir)
+ if err == nil && fi.IsDir() {
+ return nil
+ }
+
+ // To avoid cluttering the cache with extraneous files,
+ // DownloadZip uses the same lockfile as Download.
+ // Invoke DownloadZip before locking the file.
+ zipfile, err := DownloadZip(mod)
+ if err != nil {
+ return err
+ }
+
+ if cfg.CmdName != "mod download" {
+ fmt.Fprintf(os.Stderr, "go: extracting %s %s\n", mod.Path, mod.Version)
+ }
+
+ unlock, err := lockVersion(mod)
+ if err != nil {
+ return err
+ }
+ defer unlock()
+
+ // Check whether the directory was populated while we were waiting on the lock.
+ fi, err = os.Stat(dir)
+ if err == nil && fi.IsDir() {
+ return nil
+ }
+
+ // Clean up any remaining temporary directories from previous runs.
+ // This is only safe to do because the lock file ensures that their writers
+ // are no longer active.
+ parentDir := filepath.Dir(dir)
+ tmpPrefix := filepath.Base(dir) + ".tmp-"
+ if old, err := filepath.Glob(filepath.Join(parentDir, tmpPrefix+"*")); err == nil {
+ for _, path := range old {
+ RemoveAll(path) // best effort
+ }
+ }
+
+ // Extract the zip file to a temporary directory, then rename it to the
+ // final path. That way, we can use the existence of the source directory to
+ // signal that it has been extracted successfully, and if someone deletes
+ // the entire directory (e.g. as an attempt to prune out file corruption)
+ // the module cache will still be left in a recoverable state.
+ if err := os.MkdirAll(parentDir, 0777); err != nil {
+ return err
+ }
+ tmpDir, err := ioutil.TempDir(parentDir, tmpPrefix)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ if err != nil {
+ RemoveAll(tmpDir)
+ }
+ }()
+
+ modpath := mod.Path + "@" + mod.Version
+ if err := Unzip(tmpDir, zipfile, modpath, 0); err != nil {
+ fmt.Fprintf(os.Stderr, "-> %s\n", err)
+ return err
+ }
+
+ if err := os.Rename(tmpDir, dir); err != nil {
+ return err
+ }
+
+ // Make dir read-only only *after* renaming it.
+ // os.Rename was observed to fail for read-only directories on macOS.
+ makeDirsReadOnly(dir)
+ return nil
+}
+
var downloadZipCache par.Cache
// DownloadZip downloads the specific module version to the
// local zip cache and returns the name of the zip file.
func DownloadZip(mod module.Version) (zipfile string, err error) {
- // The par.Cache here avoids duplicate work but also
- // avoids conflicts from simultaneous calls by multiple goroutines
- // for the same version.
+ // The par.Cache here avoids duplicate work.
type cached struct {
zipfile string
err error
@@ -80,83 +145,134 @@ func DownloadZip(mod module.Version) (zipfile string, err error) {
if err != nil {
return cached{"", err}
}
+
+ // Skip locking if the zipfile already exists.
if _, err := os.Stat(zipfile); err == nil {
- // Use it.
- // This should only happen if the mod/cache directory is preinitialized
- // or if pkg/mod/path was removed but not pkg/mod/cache/download.
- if cfg.CmdName != "mod download" {
- fmt.Fprintf(os.Stderr, "go: extracting %s %s\n", mod.Path, mod.Version)
- }
- } else {
- if err := os.MkdirAll(filepath.Dir(zipfile), 0777); err != nil {
- return cached{"", err}
- }
- if cfg.CmdName != "mod download" {
- fmt.Fprintf(os.Stderr, "go: downloading %s %s\n", mod.Path, mod.Version)
- }
- if err := downloadZip(mod, zipfile); err != nil {
- return cached{"", err}
- }
+ return cached{zipfile, nil}
+ }
+
+ // The zip file does not exist. Acquire the lock and create it.
+ if cfg.CmdName != "mod download" {
+ fmt.Fprintf(os.Stderr, "go: downloading %s %s\n", mod.Path, mod.Version)
+ }
+ unlock, err := lockVersion(mod)
+ if err != nil {
+ return cached{"", err}
+ }
+ defer unlock()
+
+ // Double-check that the zipfile was not created while we were waiting for
+ // the lock.
+ if _, err := os.Stat(zipfile); err == nil {
+ return cached{zipfile, nil}
+ }
+ if err := os.MkdirAll(filepath.Dir(zipfile), 0777); err != nil {
+ return cached{"", err}
+ }
+ if err := downloadZip(mod, zipfile); err != nil {
+ return cached{"", err}
}
return cached{zipfile, nil}
}).(cached)
return c.zipfile, c.err
}
-func downloadZip(mod module.Version, target string) error {
- repo, err := Lookup(mod.Path)
+func downloadZip(mod module.Version, zipfile string) (err error) {
+ // Clean up any remaining tempfiles from previous runs.
+ // This is only safe to do because the lock file ensures that their
+ // writers are no longer active.
+ for _, base := range []string{zipfile, zipfile + "hash"} {
+ if old, err := filepath.Glob(renameio.Pattern(base)); err == nil {
+ for _, path := range old {
+ os.Remove(path) // best effort
+ }
+ }
+ }
+
+ // From here to the os.Rename call below is functionally almost equivalent to
+ // renameio.WriteToFile, with one key difference: we want to validate the
+ // contents of the file (by hashing it) before we commit it. Because the file
+ // is zip-compressed, we need an actual file — or at least an io.ReaderAt — to
+ // validate it: we can't just tee the stream as we write it.
+ f, err := ioutil.TempFile(filepath.Dir(zipfile), filepath.Base(renameio.Pattern(zipfile)))
if err != nil {
return err
}
- tmpfile, err := repo.Zip(mod.Version, os.TempDir())
+ defer func() {
+ if err != nil {
+ f.Close()
+ os.Remove(f.Name())
+ }
+ }()
+
+ repo, err := Lookup(mod.Path)
if err != nil {
return err
}
- defer os.Remove(tmpfile)
+ if err := repo.Zip(f, mod.Version); err != nil {
+ return err
+ }
- // Double-check zip file looks OK.
- z, err := zip.OpenReader(tmpfile)
+ // Double-check that the paths within the zip file are well-formed.
+ //
+ // TODO(bcmills): There is a similar check within the Unzip function. Can we eliminate one?
+ fi, err := f.Stat()
if err != nil {
return err
}
- prefix := mod.Path + "@" + mod.Version
+ z, err := zip.NewReader(f, fi.Size())
+ if err != nil {
+ return err
+ }
+ prefix := mod.Path + "@" + mod.Version + "/"
for _, f := range z.File {
if !strings.HasPrefix(f.Name, prefix) {
- z.Close()
return fmt.Errorf("zip for %s has unexpected file %s", prefix[:len(prefix)-1], f.Name)
}
}
- z.Close()
- hash, err := dirhash.HashZip(tmpfile, dirhash.DefaultHash)
- if err != nil {
+ // Sync the file before renaming it: otherwise, after a crash the reader may
+ // observe a 0-length file instead of the actual contents.
+ // See https://golang.org/issue/22397#issuecomment-380831736.
+ if err := f.Sync(); err != nil {
return err
}
- checkOneSum(mod, hash) // check before installing the zip file
- r, err := os.Open(tmpfile)
- if err != nil {
+ if err := f.Close(); err != nil {
return err
}
- defer r.Close()
- w, err := os.Create(target)
+
+ // Hash the zip file and check the sum before renaming to the final location.
+ hash, err := dirhash.HashZip(f.Name(), dirhash.DefaultHash)
if err != nil {
return err
}
- if _, err := io.Copy(w, r); err != nil {
- w.Close()
- return fmt.Errorf("copying: %v", err)
+ checkOneSum(mod, hash)
+
+ if err := renameio.WriteFile(zipfile+"hash", []byte(hash)); err != nil {
+ return err
}
- if err := w.Close(); err != nil {
+ if err := os.Rename(f.Name(), zipfile); err != nil {
return err
}
- return ioutil.WriteFile(target+"hash", []byte(hash), 0666)
+
+ // TODO(bcmills): Should we make the .zip and .ziphash files read-only to discourage tampering?
+
+ return nil
}
var GoSumFile string // path to go.sum; set by package modload
+type modSum struct {
+ mod module.Version
+ sum string
+}
+
var goSum struct {
mu sync.Mutex
m map[module.Version][]string // content of go.sum file (+ go.modverify if present)
+ checked map[modSum]bool // sums actually checked during execution
+ dirty bool // whether we added any new sums to m
+ overwrite bool // if true, overwrite go.sum without incorporating its contents
enabled bool // whether to use go.sum at all
modverify string // path to go.modverify, to be deleted
}
@@ -173,18 +289,25 @@ func initGoSum() bool {
}
goSum.m = make(map[module.Version][]string)
+ goSum.checked = make(map[modSum]bool)
data, err := ioutil.ReadFile(GoSumFile)
if err != nil && !os.IsNotExist(err) {
base.Fatalf("go: %v", err)
}
goSum.enabled = true
- readGoSum(GoSumFile, data)
+ readGoSum(goSum.m, GoSumFile, data)
// Add old go.modverify file.
// We'll delete go.modverify in WriteGoSum.
alt := strings.TrimSuffix(GoSumFile, ".sum") + ".modverify"
if data, err := ioutil.ReadFile(alt); err == nil {
- readGoSum(alt, data)
+ migrate := make(map[module.Version][]string)
+ readGoSum(migrate, alt, data)
+ for mod, sums := range migrate {
+ for _, sum := range sums {
+ checkOneSumLocked(mod, sum)
+ }
+ }
goSum.modverify = alt
}
return true
@@ -197,7 +320,7 @@ const emptyGoModHash = "h1:G7mAYYxgmS0lVkHyy2hEOLQCFB0DlQFTMLWggykrydY="
// readGoSum parses data, which is the content of file,
// and adds it to goSum.m. The goSum lock must be held.
-func readGoSum(file string, data []byte) {
+func readGoSum(dst map[module.Version][]string, file string, data []byte) {
lineno := 0
for len(data) > 0 {
var line []byte
@@ -221,7 +344,7 @@ func readGoSum(file string, data []byte) {
continue
}
mod := module.Version{Path: f[0], Version: f[1]}
- goSum.m[mod] = append(goSum.m[mod], f[2])
+ dst[mod] = append(dst[mod], f[2])
}
}
@@ -235,7 +358,7 @@ func checkSum(mod module.Version) {
// Do the file I/O before acquiring the go.sum lock.
ziphash, err := CachePath(mod, "ziphash")
if err != nil {
- base.Fatalf("go: verifying %s@%s: %v", mod.Path, mod.Version, err)
+ base.Fatalf("verifying %s@%s: %v", mod.Path, mod.Version, err)
}
data, err := ioutil.ReadFile(ziphash)
if err != nil {
@@ -243,11 +366,11 @@ func checkSum(mod module.Version) {
// This can happen if someone does rm -rf GOPATH/src/cache/download. So it goes.
return
}
- base.Fatalf("go: verifying %s@%s: %v", mod.Path, mod.Version, err)
+ base.Fatalf("verifying %s@%s: %v", mod.Path, mod.Version, err)
}
h := strings.TrimSpace(string(data))
if !strings.HasPrefix(h, "h1:") {
- base.Fatalf("go: verifying %s@%s: unexpected ziphash: %q", mod.Path, mod.Version, h)
+ base.Fatalf("verifying %s@%s: unexpected ziphash: %q", mod.Path, mod.Version, h)
}
checkOneSum(mod, h)
@@ -265,7 +388,7 @@ func goModSum(data []byte) (string, error) {
func checkGoMod(path, version string, data []byte) {
h, err := goModSum(data)
if err != nil {
- base.Fatalf("go: verifying %s %s go.mod: %v", path, version, err)
+ base.Fatalf("verifying %s %s go.mod: %v", path, version, err)
}
checkOneSum(module.Version{Path: path, Version: version + "/go.mod"}, h)
@@ -275,22 +398,27 @@ func checkGoMod(path, version string, data []byte) {
func checkOneSum(mod module.Version, h string) {
goSum.mu.Lock()
defer goSum.mu.Unlock()
- if !initGoSum() {
- return
+ if initGoSum() {
+ checkOneSumLocked(mod, h)
}
+}
+
+func checkOneSumLocked(mod module.Version, h string) {
+ goSum.checked[modSum{mod, h}] = true
for _, vh := range goSum.m[mod] {
if h == vh {
return
}
if strings.HasPrefix(vh, "h1:") {
- base.Fatalf("go: verifying %s@%s: checksum mismatch\n\tdownloaded: %v\n\tgo.sum: %v", mod.Path, mod.Version, h, vh)
+ base.Fatalf("verifying %s@%s: checksum mismatch\n\tdownloaded: %v\n\tgo.sum: %v", mod.Path, mod.Version, h, vh)
}
}
if len(goSum.m[mod]) > 0 {
fmt.Fprintf(os.Stderr, "warning: verifying %s@%s: unknown hashes in go.sum: %v; adding %v", mod.Path, mod.Version, strings.Join(goSum.m[mod], ", "), h)
}
goSum.m[mod] = append(goSum.m[mod], h)
+ goSum.dirty = true
}
// Sum returns the checksum for the downloaded copy of the given module,
@@ -316,10 +444,55 @@ func Sum(mod module.Version) string {
func WriteGoSum() {
goSum.mu.Lock()
defer goSum.mu.Unlock()
- if !initGoSum() {
+
+ if !goSum.enabled {
+ // If we haven't read the go.sum file yet, don't bother writing it: at best,
+ // we could rename the go.modverify file if it isn't empty, but we haven't
+ // needed to touch it so far — how important could it be?
+ return
+ }
+ if !goSum.dirty {
+ // Don't bother opening the go.sum file if we don't have anything to add.
return
}
+ // We want to avoid races between creating the lockfile and deleting it, but
+ // we also don't want to leave a permanent lockfile in the user's repository.
+ //
+ // On top of that, if we crash while writing go.sum, we don't want to lose the
+ // sums that were already present in the file, so it's important that we write
+ // the file by renaming rather than truncating — which means that we can't
+ // lock the go.sum file itself.
+ //
+ // Instead, we'll lock a distinguished file in the cache directory: that will
+ // only race if the user runs `go clean -modcache` concurrently with a command
+ // that updates go.sum, and that's already racy to begin with.
+ //
+ // We'll end up slightly over-synchronizing go.sum writes if the user runs a
+ // bunch of go commands that update sums in separate modules simultaneously,
+ // but that's unlikely to matter in practice.
+
+ unlock := SideLock()
+ defer unlock()
+
+ if !goSum.overwrite {
+ // Re-read the go.sum file to incorporate any sums added by other processes
+ // in the meantime.
+ data, err := ioutil.ReadFile(GoSumFile)
+ if err != nil && !os.IsNotExist(err) {
+ base.Fatalf("go: re-reading go.sum: %v", err)
+ }
+
+ // Add only the sums that we actually checked: the user may have edited or
+ // truncated the file to remove erroneous hashes, and we shouldn't restore
+ // them without good reason.
+ goSum.m = make(map[module.Version][]string, len(goSum.m))
+ readGoSum(goSum.m, GoSumFile, data)
+ for ms := range goSum.checked {
+ checkOneSumLocked(ms.mod, ms.sum)
+ }
+ }
+
var mods []module.Version
for m := range goSum.m {
mods = append(mods, m)
@@ -334,15 +507,16 @@ func WriteGoSum() {
}
}
- data, _ := ioutil.ReadFile(GoSumFile)
- if !bytes.Equal(data, buf.Bytes()) {
- if err := ioutil.WriteFile(GoSumFile, buf.Bytes(), 0666); err != nil {
- base.Fatalf("go: writing go.sum: %v", err)
- }
+ if err := renameio.WriteFile(GoSumFile, buf.Bytes()); err != nil {
+ base.Fatalf("go: writing go.sum: %v", err)
}
+ goSum.checked = make(map[modSum]bool)
+ goSum.dirty = false
+ goSum.overwrite = false
+
if goSum.modverify != "" {
- os.Remove(goSum.modverify)
+ os.Remove(goSum.modverify) // best effort
}
}
@@ -360,6 +534,8 @@ func TrimGoSum(keep map[module.Version]bool) {
noGoMod := module.Version{Path: m.Path, Version: strings.TrimSuffix(m.Version, "/go.mod")}
if !keep[m] && !keep[noGoMod] {
delete(goSum.m, m)
+ goSum.dirty = true
+ goSum.overwrite = true
}
}
}
diff --git a/libgo/go/cmd/go/internal/modfetch/proxy.go b/libgo/go/cmd/go/internal/modfetch/proxy.go
index 5f856b80d2e..60ed2a37966 100644
--- a/libgo/go/cmd/go/internal/modfetch/proxy.go
+++ b/libgo/go/cmd/go/internal/modfetch/proxy.go
@@ -8,7 +8,6 @@ import (
"encoding/json"
"fmt"
"io"
- "io/ioutil"
"net/url"
"os"
"strings"
@@ -209,44 +208,31 @@ func (p *proxyRepo) GoMod(version string) ([]byte, error) {
return data, nil
}
-func (p *proxyRepo) Zip(version string, tmpdir string) (tmpfile string, err error) {
+func (p *proxyRepo) Zip(dst io.Writer, version string) error {
var body io.ReadCloser
encVer, err := module.EncodeVersion(version)
if err != nil {
- return "", err
+ return err
}
err = webGetBody(p.url+"/@v/"+pathEscape(encVer)+".zip", &body)
if err != nil {
- return "", err
+ return err
}
defer body.Close()
- // Spool to local file.
- f, err := ioutil.TempFile(tmpdir, "go-proxy-download-")
- if err != nil {
- return "", err
- }
- defer f.Close()
- maxSize := int64(codehost.MaxZipFile)
- lr := &io.LimitedReader{R: body, N: maxSize + 1}
- if _, err := io.Copy(f, lr); err != nil {
- os.Remove(f.Name())
- return "", err
+ lr := &io.LimitedReader{R: body, N: codehost.MaxZipFile + 1}
+ if _, err := io.Copy(dst, lr); err != nil {
+ return err
}
if lr.N <= 0 {
- os.Remove(f.Name())
- return "", fmt.Errorf("downloaded zip file too large")
- }
- if err := f.Close(); err != nil {
- os.Remove(f.Name())
- return "", err
+ return fmt.Errorf("downloaded zip file too large")
}
- return f.Name(), nil
+ return nil
}
// pathEscape escapes s so it can be used in a path.
// That is, it escapes things like ? and # (which really shouldn't appear anyway).
// It does not escape / to %2F: our REST API is designed so that / can be left as is.
func pathEscape(s string) string {
- return strings.Replace(url.PathEscape(s), "%2F", "/", -1)
+ return strings.ReplaceAll(url.PathEscape(s), "%2F", "/")
}
diff --git a/libgo/go/cmd/go/internal/modfetch/repo.go b/libgo/go/cmd/go/internal/modfetch/repo.go
index 0ea8c1f0e35..c63f6b04221 100644
--- a/libgo/go/cmd/go/internal/modfetch/repo.go
+++ b/libgo/go/cmd/go/internal/modfetch/repo.go
@@ -6,8 +6,10 @@ package modfetch
import (
"fmt"
+ "io"
"os"
"sort"
+ "strconv"
"time"
"cmd/go/internal/cfg"
@@ -45,11 +47,8 @@ type Repo interface {
// GoMod returns the go.mod file for the given version.
GoMod(version string) (data []byte, err error)
- // Zip downloads a zip file for the given version
- // to a new file in a given temporary directory.
- // It returns the name of the new file.
- // The caller should remove the file when finished with it.
- Zip(version, tmpdir string) (tmpfile string, err error)
+ // Zip writes a zip file for the given version to dst.
+ Zip(dst io.Writer, version string) error
}
// A Rev describes a single revision in a module repository.
@@ -357,7 +356,11 @@ func (l *loggingRepo) GoMod(version string) ([]byte, error) {
return l.r.GoMod(version)
}
-func (l *loggingRepo) Zip(version, tmpdir string) (string, error) {
- defer logCall("Repo[%s]: Zip(%q, %q)", l.r.ModulePath(), version, tmpdir)()
- return l.r.Zip(version, tmpdir)
+func (l *loggingRepo) Zip(dst io.Writer, version string) error {
+ dstName := "_"
+ if dst, ok := dst.(interface{ Name() string }); ok {
+ dstName = strconv.Quote(dst.Name())
+ }
+ defer logCall("Repo[%s]: Zip(%s, %q)", l.r.ModulePath(), dstName, version)()
+ return l.r.Zip(dst, version)
}
diff --git a/libgo/go/cmd/go/internal/modfetch/unzip.go b/libgo/go/cmd/go/internal/modfetch/unzip.go
index a50431fd862..ac13ede257b 100644
--- a/libgo/go/cmd/go/internal/modfetch/unzip.go
+++ b/libgo/go/cmd/go/internal/modfetch/unzip.go
@@ -12,7 +12,6 @@ import (
"os"
"path"
"path/filepath"
- "sort"
"strings"
"cmd/go/internal/modfetch/codehost"
@@ -21,12 +20,12 @@ import (
)
func Unzip(dir, zipfile, prefix string, maxSize int64) error {
+ // TODO(bcmills): The maxSize parameter is invariantly 0. Remove it.
if maxSize == 0 {
maxSize = codehost.MaxZipFile
}
// Directory can exist, but must be empty.
- // except maybe
files, _ := ioutil.ReadDir(dir)
if len(files) > 0 {
return fmt.Errorf("target directory %v exists and is not empty", dir)
@@ -98,22 +97,16 @@ func Unzip(dir, zipfile, prefix string, maxSize int64) error {
}
// Unzip, enforcing sizes checked earlier.
- dirs := map[string]bool{dir: true}
for _, zf := range z.File {
if zf.Name == prefix || strings.HasSuffix(zf.Name, "/") {
continue
}
name := zf.Name[len(prefix):]
dst := filepath.Join(dir, name)
- parent := filepath.Dir(dst)
- for parent != dir {
- dirs[parent] = true
- parent = filepath.Dir(parent)
- }
if err := os.MkdirAll(filepath.Dir(dst), 0777); err != nil {
return err
}
- w, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0444)
+ w, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0444)
if err != nil {
return fmt.Errorf("unzip %v: %v", zipfile, err)
}
@@ -137,17 +130,44 @@ func Unzip(dir, zipfile, prefix string, maxSize int64) error {
}
}
- // Mark directories unwritable, best effort.
- var dirlist []string
- for dir := range dirs {
- dirlist = append(dirlist, dir)
+ return nil
+}
+
+// makeDirsReadOnly makes a best-effort attempt to remove write permissions for dir
+// and its transitive contents.
+func makeDirsReadOnly(dir string) {
+ type pathMode struct {
+ path string
+ mode os.FileMode
}
- sort.Strings(dirlist)
+ var dirs []pathMode // in lexical order
+ filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
+ if err == nil && info.Mode()&0222 != 0 {
+ if info.IsDir() {
+ dirs = append(dirs, pathMode{path, info.Mode()})
+ }
+ }
+ return nil
+ })
// Run over list backward to chmod children before parents.
- for i := len(dirlist) - 1; i >= 0; i-- {
- os.Chmod(dirlist[i], 0555)
+ for i := len(dirs) - 1; i >= 0; i-- {
+ os.Chmod(dirs[i].path, dirs[i].mode&^0222)
}
+}
- return nil
+// RemoveAll removes a directory written by Download or Unzip, first applying
+// any permission changes needed to do so.
+func RemoveAll(dir string) error {
+ // Module cache has 0555 directories; make them writable in order to remove content.
+ filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return nil // ignore errors walking in file system
+ }
+ if info.IsDir() {
+ os.Chmod(path, 0777)
+ }
+ return nil
+ })
+ return os.RemoveAll(dir)
}
diff --git a/libgo/go/cmd/go/internal/modfile/rule.go b/libgo/go/cmd/go/internal/modfile/rule.go
index e11f0a6e31e..7f9a18c6c2a 100644
--- a/libgo/go/cmd/go/internal/modfile/rule.go
+++ b/libgo/go/cmd/go/internal/modfile/rule.go
@@ -154,7 +154,7 @@ func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (*File
return f, nil
}
-var goVersionRE = regexp.MustCompile(`([1-9][0-9]*)\.(0|[1-9][0-9]*)`)
+var GoVersionRE = regexp.MustCompile(`([1-9][0-9]*)\.(0|[1-9][0-9]*)`)
func (f *File) add(errs *bytes.Buffer, line *Line, verb string, args []string, fix VersionFixer, strict bool) {
// If strict is false, this module is a dependency.
@@ -181,7 +181,7 @@ func (f *File) add(errs *bytes.Buffer, line *Line, verb string, args []string, f
fmt.Fprintf(errs, "%s:%d: repeated go statement\n", f.Syntax.Name, line.Start.Line)
return
}
- if len(args) != 1 || !goVersionRE.MatchString(args[0]) {
+ if len(args) != 1 || !GoVersionRE.MatchString(args[0]) {
fmt.Fprintf(errs, "%s:%d: usage: go 1.23\n", f.Syntax.Name, line.Start.Line)
return
}
@@ -477,6 +477,22 @@ func (f *File) Cleanup() {
f.Syntax.Cleanup()
}
+func (f *File) AddGoStmt(version string) error {
+ if !GoVersionRE.MatchString(version) {
+ return fmt.Errorf("invalid language version string %q", version)
+ }
+ if f.Go == nil {
+ f.Go = &Go{
+ Version: version,
+ Syntax: f.Syntax.addLine(nil, "go", version),
+ }
+ } else {
+ f.Go.Version = version
+ f.Syntax.updateLine(f.Go.Syntax, "go", version)
+ }
+ return nil
+}
+
func (f *File) AddRequire(path, vers string) error {
need := true
for _, r := range f.Require {
diff --git a/libgo/go/cmd/go/internal/modget/get.go b/libgo/go/cmd/go/internal/modget/get.go
index 90a5bd81302..2bfe6d3bb23 100644
--- a/libgo/go/cmd/go/internal/modget/get.go
+++ b/libgo/go/cmd/go/internal/modget/get.go
@@ -78,7 +78,7 @@ to use newer patch releases when available. Continuing the previous example,
In general, adding a new dependency may require upgrading
existing dependencies to keep a working build, and 'go get' does
this automatically. Similarly, downgrading one dependency may
-require downgrading other dependenceis, and 'go get' does
+require downgrading other dependencies, and 'go get' does
this automatically as well.
The -m flag instructs get to stop here, after resolving, upgrading,
@@ -247,7 +247,7 @@ func runGet(cmd *base.Command, args []string) {
// Deciding which module to upgrade/downgrade for a particular argument is difficult.
// Patterns only make it more difficult.
// We impose restrictions to avoid needing to interlace pattern expansion,
- // like in in modload.ImportPaths.
+ // like in modload.ImportPaths.
// Specifically, these patterns are supported:
//
// - Relative paths like ../../foo or ../../foo... are restricted to matching directories
@@ -281,8 +281,8 @@ func runGet(cmd *base.Command, args []string) {
base.Errorf("go get %s: %v", arg, err)
continue
}
- if !str.HasFilePathPrefix(abs, modload.ModRoot) {
- base.Errorf("go get %s: directory %s is outside module root %s", arg, abs, modload.ModRoot)
+ if !str.HasFilePathPrefix(abs, modload.ModRoot()) {
+ base.Errorf("go get %s: directory %s is outside module root %s", arg, abs, modload.ModRoot())
continue
}
// TODO: Check if abs is inside a nested module.
@@ -534,9 +534,11 @@ func runGet(cmd *base.Command, args []string) {
// module root.
continue
}
+ base.Errorf("%s", p.Error)
}
todo = append(todo, p)
}
+ base.ExitIfErrors()
// If -d was specified, we're done after the download: no build.
// (The load.PackagesAndErrors is what did the download
diff --git a/libgo/go/cmd/go/internal/modload/build.go b/libgo/go/cmd/go/internal/modload/build.go
index 558401d01f6..af89b192fe4 100644
--- a/libgo/go/cmd/go/internal/modload/build.go
+++ b/libgo/go/cmd/go/internal/modload/build.go
@@ -17,6 +17,7 @@ import (
"internal/goroot"
"os"
"path/filepath"
+ "runtime/debug"
"strings"
)
@@ -30,6 +31,9 @@ func isStandardImportPath(path string) bool {
}
func findStandardImportPath(path string) string {
+ if path == "" {
+ panic("findStandardImportPath called with empty path")
+ }
if search.IsStandardImportPath(path) {
if goroot.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, path) {
return filepath.Join(cfg.GOROOT, "src", path)
@@ -95,11 +99,13 @@ func moduleInfo(m module.Version, fromBuildList bool) *modinfo.ModulePublic {
Path: m.Path,
Version: m.Version,
Main: true,
- Dir: ModRoot,
- GoMod: filepath.Join(ModRoot, "go.mod"),
}
- if modFile.Go != nil {
- info.GoVersion = modFile.Go.Version
+ if HasModRoot() {
+ info.Dir = ModRoot()
+ info.GoMod = filepath.Join(info.Dir, "go.mod")
+ if modFile.Go != nil {
+ info.GoVersion = modFile.Go.Version
+ }
}
return info
}
@@ -114,7 +120,7 @@ func moduleInfo(m module.Version, fromBuildList bool) *modinfo.ModulePublic {
}
if cfg.BuildMod == "vendor" {
- info.Dir = filepath.Join(ModRoot, "vendor", m.Path)
+ info.Dir = filepath.Join(ModRoot(), "vendor", m.Path)
return info
}
@@ -142,34 +148,38 @@ func moduleInfo(m module.Version, fromBuildList bool) *modinfo.ModulePublic {
}
}
}
- if cfg.BuildMod == "vendor" {
- m.Dir = filepath.Join(ModRoot, "vendor", m.Path)
- }
}
- complete(info)
+ if !fromBuildList {
+ complete(info)
+ return info
+ }
- if fromBuildList {
- if r := Replacement(m); r.Path != "" {
- info.Replace = &modinfo.ModulePublic{
- Path: r.Path,
- Version: r.Version,
- GoVersion: info.GoVersion,
- }
- if r.Version == "" {
- if filepath.IsAbs(r.Path) {
- info.Replace.Dir = r.Path
- } else {
- info.Replace.Dir = filepath.Join(ModRoot, r.Path)
- }
- }
- complete(info.Replace)
- info.Dir = info.Replace.Dir
- info.GoMod = filepath.Join(info.Dir, "go.mod")
- info.Error = nil // ignore error loading original module version (it has been replaced)
- }
+ r := Replacement(m)
+ if r.Path == "" {
+ complete(info)
+ return info
}
+ // Don't hit the network to fill in extra data for replaced modules.
+ // The original resolved Version and Time don't matter enough to be
+ // worth the cost, and we're going to overwrite the GoMod and Dir from the
+ // replacement anyway. See https://golang.org/issue/27859.
+ info.Replace = &modinfo.ModulePublic{
+ Path: r.Path,
+ Version: r.Version,
+ GoVersion: info.GoVersion,
+ }
+ if r.Version == "" {
+ if filepath.IsAbs(r.Path) {
+ info.Replace.Dir = r.Path
+ } else {
+ info.Replace.Dir = filepath.Join(ModRoot(), r.Path)
+ }
+ }
+ complete(info.Replace)
+ info.Dir = info.Replace.Dir
+ info.GoMod = filepath.Join(info.Dir, "go.mod")
return info
}
@@ -177,6 +187,7 @@ func PackageBuildInfo(path string, deps []string) string {
if isStandardImportPath(path) || !Enabled() {
return ""
}
+
target := findModule(path, path)
mdeps := make(map[module.Version]bool)
for _, dep := range deps {
@@ -216,28 +227,33 @@ func PackageBuildInfo(path string, deps []string) string {
return buf.String()
}
+// findModule returns the module containing the package at path,
+// needed to build the package at target.
func findModule(target, path string) module.Version {
- // TODO: This should use loaded.
- if path == "." {
- return buildList[0]
- }
- for _, mod := range buildList {
- if maybeInModule(path, mod.Path) {
- return mod
+ pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
+ if ok {
+ if pkg.err != nil {
+ base.Fatalf("build %v: cannot load %v: %v", target, path, pkg.err)
}
+ return pkg.mod
+ }
+
+ if path == "command-line-arguments" {
+ return Target
+ }
+
+ if printStackInDie {
+ debug.PrintStack()
}
base.Fatalf("build %v: cannot find module for path %v", target, path)
panic("unreachable")
}
func ModInfoProg(info string) []byte {
- return []byte(fmt.Sprintf(`
- package main
- import _ "unsafe"
- //go:linkname __debug_modinfo__ runtime/debug.modinfo
- var __debug_modinfo__ string
- func init() {
- __debug_modinfo__ = %q
- }
+ return []byte(fmt.Sprintf(`package main
+import _ "unsafe"
+//go:linkname __set_debug_modinfo__ runtime..z2fdebug.setmodinfo
+func __set_debug_modinfo__(string)
+func init() { __set_debug_modinfo__(%q) }
`, string(infoStart)+info+string(infoEnd)))
}
diff --git a/libgo/go/cmd/go/internal/modload/help.go b/libgo/go/cmd/go/internal/modload/help.go
index f2f34197244..d9c8ae40d88 100644
--- a/libgo/go/cmd/go/internal/modload/help.go
+++ b/libgo/go/cmd/go/internal/modload/help.go
@@ -393,17 +393,20 @@ no /* */ comments. Each line holds a single directive, made up of a
verb followed by arguments. For example:
module my/thing
+ go 1.12
require other/thing v1.0.2
- require new/thing v2.3.4
+ require new/thing/v2 v2.3.4
exclude old/thing v1.2.3
replace bad/thing v1.4.5 => good/thing v1.4.5
-The verbs are module, to define the module path; require, to require
-a particular module at a given version or later; exclude, to exclude
-a particular module version from use; and replace, to replace a module
-version with a different module version. Exclude and replace apply only
-in the main module's go.mod and are ignored in dependencies.
-See https://research.swtch.com/vgo-mvs for details.
+The verbs are
+ module, to define the module path;
+ go, to set the expected language version;
+ require, to require a particular module at a given version or later;
+ exclude, to exclude a particular module version from use; and
+ replace, to replace a module version with a different module version.
+Exclude and replace apply only in the main module's go.mod and are ignored
+in dependencies. See https://research.swtch.com/vgo-mvs for details.
The leading verb can be factored out of adjacent lines to create a block,
like in Go imports:
diff --git a/libgo/go/cmd/go/internal/modload/import.go b/libgo/go/cmd/go/internal/modload/import.go
index 44c2a237267..3210e16c25b 100644
--- a/libgo/go/cmd/go/internal/modload/import.go
+++ b/libgo/go/cmd/go/internal/modload/import.go
@@ -12,13 +12,17 @@ import (
"internal/goroot"
"os"
"path/filepath"
+ "sort"
"strings"
+ "time"
"cmd/go/internal/cfg"
+ "cmd/go/internal/modfetch"
"cmd/go/internal/modfetch/codehost"
"cmd/go/internal/module"
"cmd/go/internal/par"
"cmd/go/internal/search"
+ "cmd/go/internal/semver"
)
type ImportMissingError struct {
@@ -58,9 +62,6 @@ func Import(path string) (m module.Version, dir string, err error) {
// Is the package in the standard library?
if search.IsStandardImportPath(path) {
- if strings.HasPrefix(path, "golang_org/") {
- return module.Version{}, filepath.Join(cfg.GOROOT, "src/vendor", path), nil
- }
if goroot.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, path) {
dir := filepath.Join(cfg.GOROOT, "src", path)
return module.Version{}, dir, nil
@@ -70,8 +71,8 @@ func Import(path string) (m module.Version, dir string, err error) {
// -mod=vendor is special.
// Everything must be in the main module or the main module's vendor directory.
if cfg.BuildMod == "vendor" {
- mainDir, mainOK := dirInModule(path, Target.Path, ModRoot, true)
- vendorDir, vendorOK := dirInModule(path, "", filepath.Join(ModRoot, "vendor"), false)
+ mainDir, mainOK := dirInModule(path, Target.Path, ModRoot(), true)
+ vendorDir, vendorOK := dirInModule(path, "", filepath.Join(ModRoot(), "vendor"), false)
if mainOK && vendorOK {
return module.Version{}, "", fmt.Errorf("ambiguous import: found %s in multiple directories:\n\t%s\n\t%s", path, mainDir, vendorDir)
}
@@ -125,14 +126,58 @@ func Import(path string) (m module.Version, dir string, err error) {
return module.Version{}, "", errors.New(buf.String())
}
- // Not on build list.
-
// Look up module containing the package, for addition to the build list.
// Goal is to determine the module, download it to dir, and return m, dir, ErrMissing.
if cfg.BuildMod == "readonly" {
return module.Version{}, "", fmt.Errorf("import lookup disabled by -mod=%s", cfg.BuildMod)
}
+ // Not on build list.
+ // To avoid spurious remote fetches, next try the latest replacement for each module.
+ // (golang.org/issue/26241)
+ if modFile != nil {
+ latest := map[string]string{} // path -> version
+ for _, r := range modFile.Replace {
+ if maybeInModule(path, r.Old.Path) {
+ latest[r.Old.Path] = semver.Max(r.Old.Version, latest[r.Old.Path])
+ }
+ }
+
+ mods = make([]module.Version, 0, len(latest))
+ for p, v := range latest {
+ // If the replacement didn't specify a version, synthesize a
+ // pseudo-version with an appropriate major version and a timestamp below
+ // any real timestamp. That way, if the main module is used from within
+ // some other module, the user will be able to upgrade the requirement to
+ // any real version they choose.
+ if v == "" {
+ if _, pathMajor, ok := module.SplitPathVersion(p); ok && len(pathMajor) > 0 {
+ v = modfetch.PseudoVersion(pathMajor[1:], "", time.Time{}, "000000000000")
+ } else {
+ v = modfetch.PseudoVersion("v0", "", time.Time{}, "000000000000")
+ }
+ }
+ mods = append(mods, module.Version{Path: p, Version: v})
+ }
+
+ // Every module path in mods is a prefix of the import path.
+ // As in QueryPackage, prefer the longest prefix that satisfies the import.
+ sort.Slice(mods, func(i, j int) bool {
+ return len(mods[i].Path) > len(mods[j].Path)
+ })
+ for _, m := range mods {
+ root, isLocal, err := fetch(m)
+ if err != nil {
+ // Report fetch error as above.
+ return module.Version{}, "", err
+ }
+ _, ok := dirInModule(path, m.Path, root, isLocal)
+ if ok {
+ return m, "", &ImportMissingError{ImportPath: path, Module: m}
+ }
+ }
+ }
+
m, _, err = QueryPackage(path, "latest", Allowed)
if err != nil {
if _, ok := err.(*codehost.VCSError); ok {
diff --git a/libgo/go/cmd/go/internal/modload/import_test.go b/libgo/go/cmd/go/internal/modload/import_test.go
index 3f4ddab436c..9422a3d960c 100644
--- a/libgo/go/cmd/go/internal/modload/import_test.go
+++ b/libgo/go/cmd/go/internal/modload/import_test.go
@@ -45,7 +45,7 @@ func TestImport(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
for _, tt := range importTests {
- t.Run(strings.Replace(tt.path, "/", "_", -1), func(t *testing.T) {
+ t.Run(strings.ReplaceAll(tt.path, "/", "_"), func(t *testing.T) {
// Note that there is no build list, so Import should always fail.
m, dir, err := Import(tt.path)
if err == nil {
diff --git a/libgo/go/cmd/go/internal/modload/init.go b/libgo/go/cmd/go/internal/modload/init.go
index f995bad13b5..22d14ccce78 100644
--- a/libgo/go/cmd/go/internal/modload/init.go
+++ b/libgo/go/cmd/go/internal/modload/init.go
@@ -16,27 +16,31 @@ import (
"cmd/go/internal/modfile"
"cmd/go/internal/module"
"cmd/go/internal/mvs"
+ "cmd/go/internal/renameio"
"cmd/go/internal/search"
"encoding/json"
"fmt"
+ "go/build"
"io/ioutil"
"os"
"path"
"path/filepath"
"regexp"
+ "runtime/debug"
"strconv"
"strings"
)
var (
- cwd string
+ cwd string // TODO(bcmills): Is this redundant with base.Cwd?
MustUseModules = mustUseModules()
initialized bool
- ModRoot string
- modFile *modfile.File
- excluded map[module.Version]bool
- Target module.Version
+ modRoot string
+ modFile *modfile.File
+ modFileData []byte
+ excluded map[module.Version]bool
+ Target module.Version
gopath string
@@ -53,11 +57,15 @@ var (
// To make permanent changes to the require statements
// in go.mod, edit it before calling ImportPaths or LoadBuildList.
func ModFile() *modfile.File {
+ Init()
+ if modFile == nil {
+ die()
+ }
return modFile
}
func BinDir() string {
- MustInit()
+ Init()
return filepath.Join(gopath, "bin")
}
@@ -73,6 +81,10 @@ func mustUseModules() bool {
var inGOPATH bool // running in GOPATH/src
+// Init determines whether module mode is enabled, locates the root of the
+// current module (if any), sets environment variables for Git subprocesses, and
+// configures the cfg, codehost, load, modfetch, and search packages for use
+// with modules.
func Init() {
if initialized {
return
@@ -138,6 +150,9 @@ func Init() {
}
if inGOPATH && !MustUseModules {
+ if CmdModInit {
+ die() // Don't init a module that we're just going to ignore.
+ }
// No automatic enabling in GOPATH.
if root, _ := FindModuleRoot(cwd, "", false); root != "" {
cfg.GoModInGOPATH = filepath.Join(root, "go.mod")
@@ -147,26 +162,54 @@ func Init() {
if CmdModInit {
// Running 'go mod init': go.mod will be created in current directory.
- ModRoot = cwd
+ modRoot = cwd
} else {
- ModRoot, _ = FindModuleRoot(cwd, "", MustUseModules)
- if !MustUseModules {
- if ModRoot == "" {
- return
- }
- if search.InDir(ModRoot, os.TempDir()) == "." {
- // If you create /tmp/go.mod for experimenting,
- // then any tests that create work directories under /tmp
- // will find it and get modules when they're not expecting them.
- // It's a bit of a peculiar thing to disallow but quite mysterious
- // when it happens. See golang.org/issue/26708.
- ModRoot = ""
- fmt.Fprintf(os.Stderr, "go: warning: ignoring go.mod in system temp root %v\n", os.TempDir())
+ modRoot, _ = FindModuleRoot(cwd, "", MustUseModules)
+ if modRoot == "" {
+ if !MustUseModules {
+ // GO111MODULE is 'auto' (or unset), and we can't find a module root.
+ // Stay in GOPATH mode.
return
}
+ } else if search.InDir(modRoot, os.TempDir()) == "." {
+ // If you create /tmp/go.mod for experimenting,
+ // then any tests that create work directories under /tmp
+ // will find it and get modules when they're not expecting them.
+ // It's a bit of a peculiar thing to disallow but quite mysterious
+ // when it happens. See golang.org/issue/26708.
+ modRoot = ""
+ fmt.Fprintf(os.Stderr, "go: warning: ignoring go.mod in system temp root %v\n", os.TempDir())
}
}
+ // We're in module mode. Install the hooks to make it work.
+
+ if c := cache.Default(); c == nil {
+ // With modules, there are no install locations for packages
+ // other than the build cache.
+ base.Fatalf("go: cannot use modules with build cache disabled")
+ }
+
+ list := filepath.SplitList(cfg.BuildContext.GOPATH)
+ if len(list) == 0 || list[0] == "" {
+ base.Fatalf("missing $GOPATH")
+ }
+ gopath = list[0]
+ if _, err := os.Stat(filepath.Join(gopath, "go.mod")); err == nil {
+ base.Fatalf("$GOPATH/go.mod exists but should not")
+ }
+
+ oldSrcMod := filepath.Join(list[0], "src/mod")
+ pkgMod := filepath.Join(list[0], "pkg/mod")
+ infoOld, errOld := os.Stat(oldSrcMod)
+ _, errMod := os.Stat(pkgMod)
+ if errOld == nil && infoOld.IsDir() && errMod != nil && os.IsNotExist(errMod) {
+ os.Rename(oldSrcMod, pkgMod)
+ }
+
+ modfetch.PkgMod = pkgMod
+ codehost.WorkRoot = filepath.Join(pkgMod, "cache/vcs")
+
cfg.ModulesEnabled = true
load.ModBinDir = BinDir
load.ModLookup = Lookup
@@ -177,7 +220,35 @@ func Init() {
load.ModImportFromFiles = ImportFromFiles
load.ModDirImportPath = DirImportPath
- search.SetModRoot(ModRoot)
+ if modRoot == "" {
+ // We're in module mode, but not inside a module.
+ //
+ // If the command is 'go get' or 'go list' and all of the args are in the
+ // same existing module, we could use that module's download directory in
+ // the module cache as the module root, applying any replacements and/or
+ // exclusions specified by that module. However, that would leave us in a
+ // strange state: we want 'go get' to be consistent with 'go list', and 'go
+ // list' should be able to operate on multiple modules. Moreover, the 'get'
+ // target might specify relative file paths (e.g. in the same repository) as
+ // replacements, and we would not be able to apply those anyway: we would
+ // need to either error out or ignore just those replacements, when a build
+ // from an empty module could proceed without error.
+ //
+ // Instead, we'll operate as though we're in some ephemeral external module,
+ // ignoring all replacements and exclusions uniformly.
+
+ // Normally we check sums using the go.sum file from the main module, but
+ // without a main module we do not have an authoritative go.sum file.
+ //
+ // TODO(bcmills): In Go 1.13, check sums when outside the main module.
+ //
+ // One possible approach is to merge the go.sum files from all of the
+ // modules we download: that doesn't protect us against bad top-level
+ // modules, but it at least ensures consistency for transitive dependencies.
+ } else {
+ modfetch.GoSumFile = filepath.Join(modRoot, "go.sum")
+ search.SetModRoot(modRoot)
+ }
}
func init() {
@@ -190,38 +261,41 @@ func init() {
}
// Enabled reports whether modules are (or must be) enabled.
-// If modules must be enabled but are not, Enabled returns true
+// If modules are enabled but there is no main module, Enabled returns true
// and then the first use of module information will call die
-// (usually through InitMod and MustInit).
+// (usually through MustModRoot).
func Enabled() bool {
- if !initialized {
- panic("go: Enabled called before Init")
- }
- return ModRoot != "" || MustUseModules
+ Init()
+ return modRoot != "" || MustUseModules
}
-// MustInit calls Init if needed and checks that
-// modules are enabled and the main module has been found.
-// If not, MustInit calls base.Fatalf with an appropriate message.
-func MustInit() {
- if Init(); ModRoot == "" {
+// ModRoot returns the root of the main module.
+// It calls base.Fatalf if there is no main module.
+func ModRoot() string {
+ if !HasModRoot() {
die()
}
- if c := cache.Default(); c == nil {
- // With modules, there are no install locations for packages
- // other than the build cache.
- base.Fatalf("go: cannot use modules with build cache disabled")
- }
+ return modRoot
}
-// Failed reports whether module loading failed.
-// If Failed returns true, then any use of module information will call die.
-func Failed() bool {
+// HasModRoot reports whether a main module is present.
+// HasModRoot may return false even if Enabled returns true: for example, 'get'
+// does not require a main module.
+func HasModRoot() bool {
Init()
- return cfg.ModulesEnabled && ModRoot == ""
+ return modRoot != ""
}
+// printStackInDie causes die to print a stack trace.
+//
+// It is enabled by the testgo tag, and helps to diagnose paths that
+// unexpectedly require a main module.
+var printStackInDie = false
+
func die() {
+ if printStackInDie {
+ debug.PrintStack()
+ }
if os.Getenv("GO111MODULE") == "off" {
base.Fatalf("go: modules disabled by GO111MODULE=off; see 'go help modules'")
}
@@ -231,33 +305,20 @@ func die() {
base.Fatalf("go: cannot find main module; see 'go help modules'")
}
+// InitMod sets Target and, if there is a main module, parses the initial build
+// list from its go.mod file, creating and populating that file if needed.
func InitMod() {
- MustInit()
- if modFile != nil {
+ if len(buildList) > 0 {
return
}
- list := filepath.SplitList(cfg.BuildContext.GOPATH)
- if len(list) == 0 || list[0] == "" {
- base.Fatalf("missing $GOPATH")
- }
- gopath = list[0]
- if _, err := os.Stat(filepath.Join(gopath, "go.mod")); err == nil {
- base.Fatalf("$GOPATH/go.mod exists but should not")
- }
-
- oldSrcMod := filepath.Join(list[0], "src/mod")
- pkgMod := filepath.Join(list[0], "pkg/mod")
- infoOld, errOld := os.Stat(oldSrcMod)
- _, errMod := os.Stat(pkgMod)
- if errOld == nil && infoOld.IsDir() && errMod != nil && os.IsNotExist(errMod) {
- os.Rename(oldSrcMod, pkgMod)
+ Init()
+ if modRoot == "" {
+ Target = module.Version{Path: "command-line-arguments"}
+ buildList = []module.Version{Target}
+ return
}
- modfetch.PkgMod = pkgMod
- modfetch.GoSumFile = filepath.Join(ModRoot, "go.sum")
- codehost.WorkRoot = filepath.Join(pkgMod, "cache/vcs")
-
if CmdModInit {
// Running go mod init: do legacy module conversion
legacyModInit()
@@ -266,7 +327,7 @@ func InitMod() {
return
}
- gomod := filepath.Join(ModRoot, "go.mod")
+ gomod := filepath.Join(modRoot, "go.mod")
data, err := ioutil.ReadFile(gomod)
if err != nil {
if os.IsNotExist(err) {
@@ -284,10 +345,11 @@ func InitMod() {
base.Fatalf("go: errors parsing go.mod:\n%s\n", err)
}
modFile = f
+ modFileData = data
if len(f.Syntax.Stmt) == 0 || f.Module == nil {
// Empty mod file. Must add module path.
- path, err := FindModulePath(ModRoot)
+ path, err := FindModulePath(modRoot)
if err != nil {
base.Fatalf("go: %v", err)
}
@@ -325,7 +387,7 @@ func Allowed(m module.Version) bool {
func legacyModInit() {
if modFile == nil {
- path, err := FindModulePath(ModRoot)
+ path, err := FindModulePath(modRoot)
if err != nil {
base.Fatalf("go: %v", err)
}
@@ -334,8 +396,10 @@ func legacyModInit() {
modFile.AddModuleStmt(path)
}
+ addGoStmt()
+
for _, name := range altConfigs {
- cfg := filepath.Join(ModRoot, name)
+ cfg := filepath.Join(modRoot, name)
data, err := ioutil.ReadFile(cfg)
if err == nil {
convert := modconv.Converters[name]
@@ -356,6 +420,25 @@ func legacyModInit() {
}
}
+// InitGoStmt adds a go statement, unless there already is one.
+func InitGoStmt() {
+ if modFile.Go == nil {
+ addGoStmt()
+ }
+}
+
+// addGoStmt adds a go statement referring to the current version.
+func addGoStmt() {
+ tags := build.Default.ReleaseTags
+ version := tags[len(tags)-1]
+ if !strings.HasPrefix(version, "go") || !modfile.GoVersionRE.MatchString(version[2:]) {
+ base.Fatalf("go: unrecognized default version %q", version)
+ }
+ if err := modFile.AddGoStmt(version[2:]); err != nil {
+ base.Fatalf("go: internal error: %v", err)
+ }
+}
+
var altConfigs = []string{
"Gopkg.lock",
@@ -379,7 +462,7 @@ func FindModuleRoot(dir, limit string, legacyConfigOK bool) (root, file string)
// Look for enclosing go.mod.
for {
- if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil {
+ if fi, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil && !fi.IsDir() {
return dir, "go.mod"
}
if dir == limit {
@@ -397,7 +480,7 @@ func FindModuleRoot(dir, limit string, legacyConfigOK bool) (root, file string)
dir = dir1
for {
for _, name := range altConfigs {
- if _, err := os.Stat(filepath.Join(dir, name)); err == nil {
+ if fi, err := os.Stat(filepath.Join(dir, name)); err == nil && !fi.IsDir() {
return dir, name
}
}
@@ -541,6 +624,11 @@ func WriteGoMod() {
return
}
+ // If we aren't in a module, we don't have anywhere to write a go.mod file.
+ if modRoot == "" {
+ return
+ }
+
if loaded != nil {
reqs := MinReqs()
min, err := reqs.Required(Target)
@@ -557,22 +645,53 @@ func WriteGoMod() {
modFile.SetRequire(list)
}
- file := filepath.Join(ModRoot, "go.mod")
- old, _ := ioutil.ReadFile(file)
modFile.Cleanup() // clean file after edits
new, err := modFile.Format()
if err != nil {
base.Fatalf("go: %v", err)
}
- if !bytes.Equal(old, new) {
- if cfg.BuildMod == "readonly" {
- base.Fatalf("go: updates to go.mod needed, disabled by -mod=readonly")
+
+ // Always update go.sum, even if we didn't change go.mod: we may have
+ // downloaded modules that we didn't have before.
+ modfetch.WriteGoSum()
+
+ if bytes.Equal(new, modFileData) {
+ // We don't need to modify go.mod from what we read previously.
+ // Ignore any intervening edits.
+ return
+ }
+ if cfg.BuildMod == "readonly" {
+ base.Fatalf("go: updates to go.mod needed, disabled by -mod=readonly")
+ }
+
+ unlock := modfetch.SideLock()
+ defer unlock()
+
+ file := filepath.Join(modRoot, "go.mod")
+ old, err := ioutil.ReadFile(file)
+ if !bytes.Equal(old, modFileData) {
+ if bytes.Equal(old, new) {
+ // Some other process wrote the same go.mod file that we were about to write.
+ modFileData = new
+ return
}
- if err := ioutil.WriteFile(file, new, 0666); err != nil {
- base.Fatalf("go: %v", err)
+ if err != nil {
+ base.Fatalf("go: can't determine whether go.mod has changed: %v", err)
}
+ // The contents of the go.mod file have changed. In theory we could add all
+ // of the new modules to the build list, recompute, and check whether any
+ // module in *our* build list got bumped to a different version, but that's
+ // a lot of work for marginal benefit. Instead, fail the command: if users
+ // want to run concurrent commands, they need to start with a complete,
+ // consistent module definition.
+ base.Fatalf("go: updates to go.mod needed, but contents have changed")
+
}
- modfetch.WriteGoSum()
+
+ if err := renameio.WriteFile(file, new); err != nil {
+ base.Fatalf("error writing go.mod: %v", err)
+ }
+ modFileData = new
}
func fixVersion(path, vers string) (string, error) {
diff --git a/libgo/go/cmd/go/internal/modload/init_test.go b/libgo/go/cmd/go/internal/modload/init_test.go
new file mode 100644
index 00000000000..2df9d8af7df
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modload/init_test.go
@@ -0,0 +1,42 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modload
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "testing"
+)
+
+func TestFindModuleRootIgnoreDir(t *testing.T) {
+ // In Plan 9, directories are automatically created in /n.
+ // For example, /n/go.mod always exist, but it's a directory.
+ // Test that we ignore directories when trying to find go.mod and other config files.
+
+ dir, err := ioutil.TempDir("", "gotest")
+ if err != nil {
+ t.Fatalf("failed to create temporary directory: %v", err)
+ }
+ defer os.RemoveAll(dir)
+ if err := os.Mkdir(filepath.Join(dir, "go.mod"), os.ModeDir|0755); err != nil {
+ t.Fatalf("Mkdir failed: %v", err)
+ }
+ for _, name := range altConfigs {
+ if err := os.MkdirAll(filepath.Join(dir, name), os.ModeDir|0755); err != nil {
+ t.Fatalf("MkdirAll failed: %v", err)
+ }
+ }
+ p := filepath.Join(dir, "example")
+ if err := os.Mkdir(p, os.ModeDir|0755); err != nil {
+ t.Fatalf("Mkdir failed: %v", err)
+ }
+ if root, _ := FindModuleRoot(p, "", false); root != "" {
+ t.Errorf("FindModuleRoot(%q, \"\", false): %q, want empty string", p, root)
+ }
+ if root, _ := FindModuleRoot(p, "", true); root != "" {
+ t.Errorf("FindModuleRoot(%q, \"\", true): %q, want empty string", p, root)
+ }
+}
diff --git a/libgo/go/cmd/go/internal/modload/list.go b/libgo/go/cmd/go/internal/modload/list.go
index 69a832de1df..2f1a3c24d22 100644
--- a/libgo/go/cmd/go/internal/modload/list.go
+++ b/libgo/go/cmd/go/internal/modload/list.go
@@ -17,7 +17,7 @@ import (
)
func ListModules(args []string, listU, listVersions bool) []*modinfo.ModulePublic {
- mods := listModules(args)
+ mods := listModules(args, listVersions)
if listU || listVersions {
var work par.Work
for _, m := range mods {
@@ -39,7 +39,7 @@ func ListModules(args []string, listU, listVersions bool) []*modinfo.ModulePubli
return mods
}
-func listModules(args []string) []*modinfo.ModulePublic {
+func listModules(args []string, listVersions bool) []*modinfo.ModulePublic {
LoadBuildList()
if len(args) == 0 {
return []*modinfo.ModulePublic{moduleInfo(buildList[0], true)}
@@ -83,6 +83,10 @@ func listModules(args []string) []*modinfo.ModulePublic {
}
matched := false
for i, m := range buildList {
+ if i == 0 && !HasModRoot() {
+ // The root module doesn't actually exist: omit it.
+ continue
+ }
if match(m.Path) {
matched = true
if !matchedBuildList[i] {
@@ -93,6 +97,16 @@ func listModules(args []string) []*modinfo.ModulePublic {
}
if !matched {
if literal {
+ if listVersions {
+ // Don't make the user provide an explicit '@latest' when they're
+ // explicitly asking what the available versions are.
+ // Instead, resolve the module, even if it isn't an existing dependency.
+ info, err := Query(arg, "latest", nil)
+ if err == nil {
+ mods = append(mods, moduleInfo(module.Version{Path: arg, Version: info.Version}, false))
+ continue
+ }
+ }
mods = append(mods, &modinfo.ModulePublic{
Path: arg,
Error: &modinfo.ModuleError{
diff --git a/libgo/go/cmd/go/internal/modload/load.go b/libgo/go/cmd/go/internal/modload/load.go
index 5bf6c9b1cf9..9a1fb76bb95 100644
--- a/libgo/go/cmd/go/internal/modload/load.go
+++ b/libgo/go/cmd/go/internal/modload/load.go
@@ -90,7 +90,7 @@ func ImportPaths(patterns []string) []*search.Match {
// the exact version of a particular module increases during
// the loader iterations.
m.Pkgs = str.StringList(fsDirs[i])
- for i, pkg := range m.Pkgs {
+ for j, pkg := range m.Pkgs {
dir := pkg
if !filepath.IsAbs(dir) {
dir = filepath.Join(cwd, pkg)
@@ -101,10 +101,10 @@ func ImportPaths(patterns []string) []*search.Match {
// Note: The checks for @ here are just to avoid misinterpreting
// the module cache directories (formerly GOPATH/src/mod/foo@v1.5.2/bar).
// It's not strictly necessary but helpful to keep the checks.
- if dir == ModRoot {
+ if modRoot != "" && dir == modRoot {
pkg = Target.Path
- } else if strings.HasPrefix(dir, ModRoot+string(filepath.Separator)) && !strings.Contains(dir[len(ModRoot):], "@") {
- suffix := filepath.ToSlash(dir[len(ModRoot):])
+ } else if modRoot != "" && strings.HasPrefix(dir, modRoot+string(filepath.Separator)) && !strings.Contains(dir[len(modRoot):], "@") {
+ suffix := filepath.ToSlash(dir[len(modRoot):])
if strings.HasPrefix(suffix, "/vendor/") {
// TODO getmode vendor check
pkg = strings.TrimPrefix(suffix, "/vendor/")
@@ -118,24 +118,21 @@ func ImportPaths(patterns []string) []*search.Match {
} else {
pkg = ""
if !iterating {
+ ModRoot()
base.Errorf("go: directory %s outside available modules", base.ShortPath(dir))
}
}
info, err := os.Stat(dir)
if err != nil || !info.IsDir() {
- // If the directory does not exist,
- // don't turn it into an import path
- // that will trigger a lookup.
- pkg = ""
- if !iterating {
- if err != nil {
- base.Errorf("go: no such directory %v", m.Pattern)
- } else {
- base.Errorf("go: %s is not a directory", m.Pattern)
- }
+ // If the directory is local but does not exist, don't return it
+ // while loader is iterating, since this would trigger a fetch.
+ // After loader is done iterating, we still need to return the
+ // path, so that "go list -e" produces valid output.
+ if iterating {
+ pkg = ""
}
}
- m.Pkgs[i] = pkg
+ m.Pkgs[j] = pkg
}
case strings.Contains(m.Pattern, "..."):
@@ -251,17 +248,21 @@ func ImportFromFiles(gofiles []string) {
// DirImportPath returns the effective import path for dir,
// provided it is within the main module, or else returns ".".
func DirImportPath(dir string) string {
+ if modRoot == "" {
+ return "."
+ }
+
if !filepath.IsAbs(dir) {
dir = filepath.Join(cwd, dir)
} else {
dir = filepath.Clean(dir)
}
- if dir == ModRoot {
+ if dir == modRoot {
return Target.Path
}
- if strings.HasPrefix(dir, ModRoot+string(filepath.Separator)) {
- suffix := filepath.ToSlash(dir[len(ModRoot):])
+ if strings.HasPrefix(dir, modRoot+string(filepath.Separator)) {
+ suffix := filepath.ToSlash(dir[len(modRoot):])
if strings.HasPrefix(suffix, "/vendor/") {
return strings.TrimPrefix(suffix, "/vendor/")
}
@@ -397,6 +398,9 @@ func ModuleUsedDirectly(path string) bool {
// Lookup requires that one of the Load functions in this package has already
// been called.
func Lookup(path string) (dir, realPath string, err error) {
+ if path == "" {
+ panic("Lookup called with empty package path")
+ }
pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
if !ok {
// The loader should have found all the relevant paths.
@@ -762,7 +766,7 @@ func (pkg *loadPkg) stackText() string {
}
// why returns the text to use in "go mod why" output about the given package.
-// It is less ornate than the stackText but conatins the same information.
+// It is less ornate than the stackText but contains the same information.
func (pkg *loadPkg) why() string {
var buf strings.Builder
var stack []*loadPkg
@@ -811,7 +815,7 @@ func WhyDepth(path string) int {
// a module.Version with Path == "".
func Replacement(mod module.Version) module.Version {
if modFile == nil {
- // Happens during testing.
+ // Happens during testing and if invoking 'go get' or 'go list' outside a module.
return module.Version{}
}
@@ -888,7 +892,7 @@ func readVendorList() {
vendorOnce.Do(func() {
vendorList = nil
vendorMap = make(map[string]module.Version)
- data, _ := ioutil.ReadFile(filepath.Join(ModRoot, "vendor/modules.txt"))
+ data, _ := ioutil.ReadFile(filepath.Join(ModRoot(), "vendor/modules.txt"))
var m module.Version
for _, line := range strings.Split(string(data), "\n") {
if strings.HasPrefix(line, "# ") {
@@ -918,7 +922,7 @@ func (r *mvsReqs) modFileToList(f *modfile.File) []module.Version {
func (r *mvsReqs) required(mod module.Version) ([]module.Version, error) {
if mod == Target {
- if modFile.Go != nil {
+ if modFile != nil && modFile.Go != nil {
r.versions.LoadOrStore(mod, modFile.Go.Version)
}
var list []module.Version
@@ -938,7 +942,7 @@ func (r *mvsReqs) required(mod module.Version) ([]module.Version, error) {
// TODO: need to slip the new version into the tags list etc.
dir := repl.Path
if !filepath.IsAbs(dir) {
- dir = filepath.Join(ModRoot, dir)
+ dir = filepath.Join(ModRoot(), dir)
}
gomod := filepath.Join(dir, "go.mod")
data, err := ioutil.ReadFile(gomod)
@@ -1053,13 +1057,13 @@ func (*mvsReqs) next(m module.Version) (module.Version, error) {
func fetch(mod module.Version) (dir string, isLocal bool, err error) {
if mod == Target {
- return ModRoot, true, nil
+ return ModRoot(), true, nil
}
if r := Replacement(mod); r.Path != "" {
if r.Version == "" {
dir = r.Path
if !filepath.IsAbs(dir) {
- dir = filepath.Join(ModRoot, dir)
+ dir = filepath.Join(ModRoot(), dir)
}
return dir, true, nil
}
diff --git a/libgo/go/cmd/go/internal/modload/query.go b/libgo/go/cmd/go/internal/modload/query.go
index 3b550f1db7f..0856486c212 100644
--- a/libgo/go/cmd/go/internal/modload/query.go
+++ b/libgo/go/cmd/go/internal/modload/query.go
@@ -207,21 +207,23 @@ func matchSemverPrefix(p, v string) bool {
// If multiple modules with revisions matching the query provide the requested
// package, QueryPackage picks the one with the longest module path.
//
-// If the path is in the the main module and the query is "latest",
+// If the path is in the main module and the query is "latest",
// QueryPackage returns Target as the version.
func QueryPackage(path, query string, allowed func(module.Version) bool) (module.Version, *modfetch.RevInfo, error) {
- if _, ok := dirInModule(path, Target.Path, ModRoot, true); ok {
- if query != "latest" {
- return module.Version{}, nil, fmt.Errorf("can't query specific version (%q) for package %s in the main module (%s)", query, path, Target.Path)
- }
- if !allowed(Target) {
- return module.Version{}, nil, fmt.Errorf("internal error: package %s is in the main module (%s), but version is not allowed", path, Target.Path)
+ if HasModRoot() {
+ if _, ok := dirInModule(path, Target.Path, modRoot, true); ok {
+ if query != "latest" {
+ return module.Version{}, nil, fmt.Errorf("can't query specific version (%q) for package %s in the main module (%s)", query, path, Target.Path)
+ }
+ if !allowed(Target) {
+ return module.Version{}, nil, fmt.Errorf("internal error: package %s is in the main module (%s), but version is not allowed", path, Target.Path)
+ }
+ return Target, &modfetch.RevInfo{Version: Target.Version}, nil
}
- return Target, &modfetch.RevInfo{Version: Target.Version}, nil
}
finalErr := errMissing
- for p := path; p != "."; p = pathpkg.Dir(p) {
+ for p := path; p != "." && p != "/"; p = pathpkg.Dir(p) {
info, err := Query(p, query, allowed)
if err != nil {
if _, ok := err.(*codehost.VCSError); ok {
diff --git a/libgo/go/cmd/go/internal/modload/query_test.go b/libgo/go/cmd/go/internal/modload/query_test.go
index 7f3ffabef74..9b073832171 100644
--- a/libgo/go/cmd/go/internal/modload/query_test.go
+++ b/libgo/go/cmd/go/internal/modload/query_test.go
@@ -132,7 +132,7 @@ func TestQuery(t *testing.T) {
ok, _ := path.Match(allow, m.Version)
return ok
}
- t.Run(strings.Replace(tt.path, "/", "_", -1)+"/"+tt.query+"/"+allow, func(t *testing.T) {
+ t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.query+"/"+allow, func(t *testing.T) {
info, err := Query(tt.path, tt.query, allowed)
if tt.err != "" {
if err != nil && err.Error() == tt.err {
diff --git a/libgo/go/cmd/go/internal/modload/search.go b/libgo/go/cmd/go/internal/modload/search.go
index 24825cc35d8..7d8852d01d7 100644
--- a/libgo/go/cmd/go/internal/modload/search.go
+++ b/libgo/go/cmd/go/internal/modload/search.go
@@ -118,7 +118,10 @@ func matchPackages(pattern string, tags map[string]bool, useStd bool, modules []
}
var root string
if mod.Version == "" {
- root = ModRoot
+ if !HasModRoot() {
+ continue // If there is no main module, we can't search in it.
+ }
+ root = ModRoot()
} else {
var err error
root, _, err = fetch(mod)
diff --git a/libgo/go/cmd/go/internal/modload/testgo.go b/libgo/go/cmd/go/internal/modload/testgo.go
new file mode 100644
index 00000000000..663b24a68d7
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modload/testgo.go
@@ -0,0 +1,11 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//+build testgo
+
+package modload
+
+func init() {
+ printStackInDie = true
+}
diff --git a/libgo/go/cmd/go/internal/module/module.go b/libgo/go/cmd/go/internal/module/module.go
index 1dbb0f5cb79..481a90b1c46 100644
--- a/libgo/go/cmd/go/internal/module/module.go
+++ b/libgo/go/cmd/go/internal/module/module.go
@@ -226,7 +226,7 @@ func checkElem(elem string, fileName bool) error {
}
for _, bad := range badWindowsNames {
if strings.EqualFold(bad, short) {
- return fmt.Errorf("disallowed path element %q", elem)
+ return fmt.Errorf("%q disallowed as path element component on Windows", short)
}
}
return nil
@@ -284,7 +284,7 @@ func SplitPathVersion(path string) (prefix, pathMajor string, ok bool) {
}
i--
}
- if i <= 1 || path[i-1] != 'v' || path[i-2] != '/' {
+ if i <= 1 || i == len(path) || path[i-1] != 'v' || path[i-2] != '/' {
return path, "", true
}
prefix, pathMajor = path[:i-2], path[i-2:]
diff --git a/libgo/go/cmd/go/internal/module/module_test.go b/libgo/go/cmd/go/internal/module/module_test.go
index f21d620d328..b40bd03dfa6 100644
--- a/libgo/go/cmd/go/internal/module/module_test.go
+++ b/libgo/go/cmd/go/internal/module/module_test.go
@@ -214,6 +214,7 @@ var splitPathVersionTests = []struct {
{"x.y/z", ""},
{"x.y/z", "/v2"},
{"x.y/z", "/v3"},
+ {"x.y/v", ""},
{"gopkg.in/yaml", ".v0"},
{"gopkg.in/yaml", ".v1"},
{"gopkg.in/yaml", ".v2"},
diff --git a/libgo/go/cmd/go/internal/mvs/mvs.go b/libgo/go/cmd/go/internal/mvs/mvs.go
index 8ec9162dabc..aa109693f30 100644
--- a/libgo/go/cmd/go/internal/mvs/mvs.go
+++ b/libgo/go/cmd/go/internal/mvs/mvs.go
@@ -68,6 +68,7 @@ func (e *MissingModuleError) Error() string {
}
// BuildList returns the build list for the target module.
+// The first element is the target itself, with the remainder of the list sorted by path.
func BuildList(target module.Version, reqs Reqs) ([]module.Version, error) {
return buildList(target, reqs, nil)
}
diff --git a/libgo/go/cmd/go/internal/renameio/renameio.go b/libgo/go/cmd/go/internal/renameio/renameio.go
new file mode 100644
index 00000000000..8f59e1a5773
--- /dev/null
+++ b/libgo/go/cmd/go/internal/renameio/renameio.go
@@ -0,0 +1,63 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package renameio writes files atomically by renaming temporary files.
+package renameio
+
+import (
+ "bytes"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+)
+
+const patternSuffix = "*.tmp"
+
+// Pattern returns a glob pattern that matches the unrenamed temporary files
+// created when writing to filename.
+func Pattern(filename string) string {
+ return filepath.Join(filepath.Dir(filename), filepath.Base(filename)+patternSuffix)
+}
+
+// WriteFile is like ioutil.WriteFile, but first writes data to an arbitrary
+// file in the same directory as filename, then renames it atomically to the
+// final name.
+//
+// That ensures that the final location, if it exists, is always a complete file.
+func WriteFile(filename string, data []byte) (err error) {
+ return WriteToFile(filename, bytes.NewReader(data))
+}
+
+// WriteToFile is a variant of WriteFile that accepts the data as an io.Reader
+// instead of a slice.
+func WriteToFile(filename string, data io.Reader) (err error) {
+ f, err := ioutil.TempFile(filepath.Dir(filename), filepath.Base(filename)+patternSuffix)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ // Only call os.Remove on f.Name() if we failed to rename it: otherwise,
+ // some other process may have created a new file with the same name after
+ // that.
+ if err != nil {
+ f.Close()
+ os.Remove(f.Name())
+ }
+ }()
+
+ if _, err := io.Copy(f, data); err != nil {
+ return err
+ }
+ // Sync the file before renaming it: otherwise, after a crash the reader may
+ // observe a 0-length file instead of the actual contents.
+ // See https://golang.org/issue/22397#issuecomment-380831736.
+ if err := f.Sync(); err != nil {
+ return err
+ }
+ if err := f.Close(); err != nil {
+ return err
+ }
+ return os.Rename(f.Name(), filename)
+}
diff --git a/libgo/go/cmd/go/internal/run/run.go b/libgo/go/cmd/go/internal/run/run.go
index 303e6842e7b..feccf23b278 100644
--- a/libgo/go/cmd/go/internal/run/run.go
+++ b/libgo/go/cmd/go/internal/run/run.go
@@ -78,6 +78,9 @@ func runRun(cmd *base.Command, args []string) {
p = load.GoFilesPackage(files)
} else if len(args) > 0 && !strings.HasPrefix(args[0], "-") {
pkgs := load.PackagesAndErrors(args[:1])
+ if len(pkgs) == 0 {
+ base.Fatalf("go run: no packages loaded from %s", args[0])
+ }
if len(pkgs) > 1 {
var names []string
for _, p := range pkgs {
diff --git a/libgo/go/cmd/go/internal/search/search.go b/libgo/go/cmd/go/internal/search/search.go
index 60ae73696bb..0ca60e73497 100644
--- a/libgo/go/cmd/go/internal/search/search.go
+++ b/libgo/go/cmd/go/internal/search/search.go
@@ -275,7 +275,7 @@ func MatchPattern(pattern string) func(name string) bool {
case strings.HasSuffix(re, `/\.\.\.`):
re = strings.TrimSuffix(re, `/\.\.\.`) + `(/\.\.\.)?`
}
- re = strings.Replace(re, `\.\.\.`, `[^`+vendorChar+`]*`, -1)
+ re = strings.ReplaceAll(re, `\.\.\.`, `[^`+vendorChar+`]*`)
reg := regexp.MustCompile(`^` + re + `$`)
@@ -353,7 +353,7 @@ func CleanPatterns(patterns []string) []string {
// as a courtesy to Windows developers, rewrite \ to /
// in command-line arguments. Handles .\... and so on.
if filepath.Separator == '\\' {
- a = strings.Replace(a, `\`, `/`, -1)
+ a = strings.ReplaceAll(a, `\`, `/`)
}
// Put argument in canonical form, but preserve leading ./.
diff --git a/libgo/go/cmd/go/internal/semver/semver.go b/libgo/go/cmd/go/internal/semver/semver.go
index 4af7118e55d..122e612dd4b 100644
--- a/libgo/go/cmd/go/internal/semver/semver.go
+++ b/libgo/go/cmd/go/internal/semver/semver.go
@@ -263,7 +263,7 @@ func parseBuild(v string) (t, rest string, ok bool) {
i := 1
start := 1
for i < len(v) {
- if !isIdentChar(v[i]) {
+ if !isIdentChar(v[i]) && v[i] != '.' {
return
}
if v[i] == '.' {
diff --git a/libgo/go/cmd/go/internal/semver/semver_test.go b/libgo/go/cmd/go/internal/semver/semver_test.go
index 96b64a58075..77025a44abd 100644
--- a/libgo/go/cmd/go/internal/semver/semver_test.go
+++ b/libgo/go/cmd/go/internal/semver/semver_test.go
@@ -44,6 +44,7 @@ var tests = []struct {
{"v1.2.3", "v1.2.3"},
{"v1.2.3+meta", "v1.2.3"},
{"v1.2.3+meta-pre", "v1.2.3"},
+ {"v1.2.3+meta-pre.sha.256a", "v1.2.3"},
}
func TestIsValid(t *testing.T) {
diff --git a/libgo/go/cmd/go/internal/test/test.go b/libgo/go/cmd/go/internal/test/test.go
index a089f1b134a..332f3124415 100644
--- a/libgo/go/cmd/go/internal/test/test.go
+++ b/libgo/go/cmd/go/internal/test/test.go
@@ -27,6 +27,7 @@ import (
"cmd/go/internal/cache"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
+ "cmd/go/internal/lockedfile"
"cmd/go/internal/modload"
"cmd/go/internal/str"
"cmd/go/internal/work"
@@ -124,16 +125,6 @@ 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.
-
-For more about build flags, see 'go help build'.
-For more about specifying packages, see 'go help packages'.
-
-See also: go build, go vet.
-`,
-}
-
-const testFlag1 = `
In addition to the build flags, the flags handled by 'go test' itself are:
-args
@@ -164,15 +155,13 @@ In addition to the build flags, the flags handled by 'go test' itself are:
The test still runs (unless -c or -i is specified).
The test binary also accepts flags that control execution of the test; these
-flags are also accessible by 'go test'.
-`
-
-// Usage prints the usage message for 'go test -h' and exits.
-func Usage() {
- os.Stderr.WriteString("usage: " + testUsage + "\n\n" +
- strings.TrimSpace(testFlag1) + "\n\n\t" +
- strings.TrimSpace(testFlag2) + "\n")
- os.Exit(2)
+flags are also accessible by 'go test'. See 'go help testflag' for details.
+
+For more about build flags, see 'go help build'.
+For more about specifying packages, see 'go help packages'.
+
+See also: go build, go vet.
+`,
}
var HelpTestflag = &base.Command{
@@ -190,11 +179,6 @@ options of pprof control how the information is presented.
The following flags are recognized by the 'go test' command and
control the execution of any test:
- ` + strings.TrimSpace(testFlag2) + `
-`,
-}
-
-const testFlag2 = `
-bench regexp
Run only those benchmarks matching a regular expression.
By default, no benchmarks are run.
@@ -212,6 +196,8 @@ const testFlag2 = `
Run enough iterations of each benchmark to take t, specified
as a time.Duration (for example, -benchtime 1h30s).
The default is 1 second (1s).
+ The special syntax Nx means to run the benchmark N times
+ (for example, -benchtime 100x).
-count n
Run each test and benchmark n times (default 1).
@@ -412,7 +398,8 @@ In the first example, the -x and the second -v are passed through to the
test binary unchanged and with no effect on the go command itself.
In the second example, the argument math is passed through to the test
binary, instead of being interpreted as the package list.
-`
+`,
+}
var HelpTestfunc = &base.Command{
UsageLine: "testfunc",
@@ -530,7 +517,7 @@ var testVetFlags = []string{
func runTest(cmd *base.Command, args []string) {
modload.LoadTests = true
- pkgArgs, testArgs = testFlags(args)
+ pkgArgs, testArgs = testFlags(cmd.Usage, args)
work.FindExecCmd() // initialize cached result
@@ -580,7 +567,7 @@ func runTest(cmd *base.Command, args []string) {
// (We implement go clean -testcache by writing an expiration date
// instead of searching out and deleting test result cache entries.)
if dir := cache.DefaultDir(); dir != "off" {
- if data, _ := ioutil.ReadFile(filepath.Join(dir, "testexpire.txt")); len(data) > 0 && data[len(data)-1] == '\n' {
+ if data, _ := lockedfile.Read(filepath.Join(dir, "testexpire.txt")); len(data) > 0 && data[len(data)-1] == '\n' {
if t, err := strconv.ParseInt(string(data[:len(data)-1]), 10, 64); err == nil {
testCacheExpire = time.Unix(0, t)
}
@@ -885,15 +872,19 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
target = filepath.Join(base.Cwd, target)
}
}
- pmain.Target = target
- installAction = &work.Action{
- Mode: "test build",
- Func: work.BuildInstallFunc,
- Deps: []*work.Action{buildAction},
- Package: pmain,
- Target: target,
+ if target == os.DevNull {
+ runAction = buildAction
+ } else {
+ pmain.Target = target
+ installAction = &work.Action{
+ Mode: "test build",
+ Func: work.BuildInstallFunc,
+ Deps: []*work.Action{buildAction},
+ Package: pmain,
+ Target: target,
+ }
+ runAction = installAction // make sure runAction != nil even if not running test
}
- runAction = installAction // make sure runAction != nil even if not running test
}
var vetRunAction *work.Action
if testC {
diff --git a/libgo/go/cmd/go/internal/test/testflag.go b/libgo/go/cmd/go/internal/test/testflag.go
index 73f8c69d9e1..ebcf49a4e9c 100644
--- a/libgo/go/cmd/go/internal/test/testflag.go
+++ b/libgo/go/cmd/go/internal/test/testflag.go
@@ -87,7 +87,7 @@ func init() {
// to allow both
// go test fmt -custom-flag-for-fmt-test
// go test -x math
-func testFlags(args []string) (packageNames, passToTest []string) {
+func testFlags(usage func(), args []string) (packageNames, passToTest []string) {
args = str.StringList(cmdflag.FindGOFLAGS(testFlagDefn), args)
inPkg := false
var explicitArgs []string
@@ -108,7 +108,7 @@ func testFlags(args []string) (packageNames, passToTest []string) {
inPkg = false
}
- f, value, extraWord := cmdflag.Parse(cmd, testFlagDefn, args, i)
+ f, value, extraWord := cmdflag.Parse(cmd, usage, testFlagDefn, args, i)
if f == nil {
// This is a flag we do not know; we must assume
// that any args we see after this might be flag
diff --git a/libgo/go/cmd/go/internal/vet/vet.go b/libgo/go/cmd/go/internal/vet/vet.go
index ea85fb8d5c9..3d828a2a4a4 100644
--- a/libgo/go/cmd/go/internal/vet/vet.go
+++ b/libgo/go/cmd/go/internal/vet/vet.go
@@ -16,17 +16,26 @@ import (
var CmdVet = &base.Command{
Run: runVet,
CustomFlags: true,
- UsageLine: "go vet [-n] [-x] [build flags] [vet flags] [packages]",
+ UsageLine: "go vet [-n] [-x] [-vettool prog] [build flags] [vet flags] [packages]",
Short: "report likely mistakes in packages",
Long: `
Vet runs the Go vet command on the packages named by the import paths.
For more about vet and its flags, see 'go doc cmd/vet'.
For more about specifying packages, see 'go help packages'.
+For a list of checkers and their flags, see 'go tool vet help'.
+For details of a specific checker such as 'printf', see 'go tool vet help printf'.
The -n flag prints commands that would be executed.
The -x flag prints commands as they are executed.
+The -vettool=prog flag selects a different analysis tool with alternative
+or additional checks.
+For example, the 'shadow' analyzer can be built and run using these commands:
+
+ go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow
+ go vet -vettool=$(which shadow)
+
The build flags supported by go vet are those that control package resolution
and execution, such as -n, -x, -v, -tags, and -toolexec.
For more about these flags, see 'go help build'.
@@ -38,7 +47,7 @@ See also: go fmt, go fix.
func runVet(cmd *base.Command, args []string) {
modload.LoadTests = true
- vetFlags, pkgArgs := vetFlags(args)
+ vetFlags, pkgArgs := vetFlags(vetUsage, args)
work.BuildInit()
work.VetFlags = vetFlags
diff --git a/libgo/go/cmd/go/internal/vet/vetflag.go b/libgo/go/cmd/go/internal/vet/vetflag.go
index 50eac425ec3..37342f41633 100644
--- a/libgo/go/cmd/go/internal/vet/vetflag.go
+++ b/libgo/go/cmd/go/internal/vet/vetflag.go
@@ -5,9 +5,14 @@
package vet
import (
+ "bytes"
+ "encoding/json"
"flag"
"fmt"
+ "log"
"os"
+ "os/exec"
+ "path/filepath"
"strings"
"cmd/go/internal/base"
@@ -16,72 +21,116 @@ import (
"cmd/go/internal/work"
)
-const cmd = "vet"
-
-// vetFlagDefn is the set of flags we process.
-var vetFlagDefn = []*cmdflag.Defn{
- // Note: Some flags, in particular -tags and -v, are known to
- // vet but also defined as build flags. This works fine, so we
- // don't define them here but use AddBuildFlags to init them.
- // However some, like -x, are known to the build but not
- // to vet. We handle them in vetFlags.
-
- // local.
- {Name: "all", BoolVar: new(bool), PassToTest: true},
- {Name: "asmdecl", BoolVar: new(bool), PassToTest: true},
- {Name: "assign", BoolVar: new(bool), PassToTest: true},
- {Name: "atomic", BoolVar: new(bool), PassToTest: true},
- {Name: "bool", BoolVar: new(bool), PassToTest: true},
- {Name: "buildtags", BoolVar: new(bool), PassToTest: true},
- {Name: "cgocall", BoolVar: new(bool), PassToTest: true},
- {Name: "composites", BoolVar: new(bool), PassToTest: true},
- {Name: "copylocks", BoolVar: new(bool), PassToTest: true},
- {Name: "httpresponse", BoolVar: new(bool), PassToTest: true},
- {Name: "lostcancel", BoolVar: new(bool), PassToTest: true},
- {Name: "methods", BoolVar: new(bool), PassToTest: true},
- {Name: "nilfunc", BoolVar: new(bool), PassToTest: true},
- {Name: "printf", BoolVar: new(bool), PassToTest: true},
- {Name: "printfuncs", PassToTest: true},
- {Name: "rangeloops", BoolVar: new(bool), PassToTest: true},
- {Name: "shadow", BoolVar: new(bool), PassToTest: true},
- {Name: "shadowstrict", BoolVar: new(bool), PassToTest: true},
- {Name: "shift", BoolVar: new(bool), PassToTest: true},
- {Name: "source", BoolVar: new(bool), PassToTest: true},
- {Name: "structtags", BoolVar: new(bool), PassToTest: true},
- {Name: "tests", BoolVar: new(bool), PassToTest: true},
- {Name: "unreachable", BoolVar: new(bool), PassToTest: true},
- {Name: "unsafeptr", BoolVar: new(bool), PassToTest: true},
- {Name: "unusedfuncs", PassToTest: true},
- {Name: "unusedresult", BoolVar: new(bool), PassToTest: true},
- {Name: "unusedstringmethods", PassToTest: true},
-}
+// go vet flag processing
+//
+// We query the flags of the tool specified by -vettool and accept any
+// of those flags plus any flag valid for 'go build'. The tool must
+// support -flags, which prints a description of its flags in JSON to
+// stdout.
-var vetTool string
+// vetTool specifies the vet command to run.
+// Any tool that supports the (still unpublished) vet
+// command-line protocol may be supplied; see
+// golang.org/x/tools/go/analysis/unitchecker for one
+// implementation. It is also used by tests.
+//
+// The default behavior (vetTool=="") runs 'go tool vet'.
+//
+var vetTool string // -vettool
-// add build flags to vetFlagDefn.
func init() {
- cmdflag.AddKnownFlags("vet", vetFlagDefn)
+ // Extract -vettool by ad hoc flag processing:
+ // its value is needed even before we can declare
+ // the flags available during main flag processing.
+ for i, arg := range os.Args {
+ if arg == "-vettool" || arg == "--vettool" {
+ if i+1 >= len(os.Args) {
+ log.Fatalf("%s requires a filename", arg)
+ }
+ vetTool = os.Args[i+1]
+ break
+ } else if strings.HasPrefix(arg, "-vettool=") ||
+ strings.HasPrefix(arg, "--vettool=") {
+ vetTool = arg[strings.IndexByte(arg, '=')+1:]
+ break
+ }
+ }
+}
+
+// vetFlags processes the command line, splitting it at the first non-flag
+// into the list of flags and list of packages.
+func vetFlags(usage func(), args []string) (passToVet, packageNames []string) {
+ // Query the vet command for its flags.
+ tool := vetTool
+ if tool != "" {
+ var err error
+ tool, err = filepath.Abs(tool)
+ if err != nil {
+ log.Fatal(err)
+ }
+ } else {
+ tool = base.Tool("vet")
+ }
+ out := new(bytes.Buffer)
+ vetcmd := exec.Command(tool, "-flags")
+ vetcmd.Stdout = out
+ if err := vetcmd.Run(); err != nil {
+ fmt.Fprintf(os.Stderr, "go vet: can't execute %s -flags: %v\n", tool, err)
+ os.Exit(2)
+ }
+ var analysisFlags []struct {
+ Name string
+ Bool bool
+ Usage string
+ }
+ if err := json.Unmarshal(out.Bytes(), &analysisFlags); err != nil {
+ fmt.Fprintf(os.Stderr, "go vet: can't unmarshal JSON from %s -flags: %v", tool, err)
+ os.Exit(2)
+ }
+
+ // Add vet's flags to vetflagDefn.
+ //
+ // Some flags, in particular -tags and -v, are known to vet but
+ // also defined as build flags. This works fine, so we don't
+ // define them here but use AddBuildFlags to init them.
+ // However some, like -x, are known to the build but not to vet.
+ var vetFlagDefn []*cmdflag.Defn
+ for _, f := range analysisFlags {
+ switch f.Name {
+ case "tags", "v":
+ continue
+ }
+ defn := &cmdflag.Defn{
+ Name: f.Name,
+ PassToTest: true,
+ }
+ if f.Bool {
+ defn.BoolVar = new(bool)
+ }
+ vetFlagDefn = append(vetFlagDefn, defn)
+ }
+
+ // Add build flags to vetFlagDefn.
var cmd base.Command
work.AddBuildFlags(&cmd)
- cmd.Flag.StringVar(&vetTool, "vettool", "", "path to vet tool binary") // for cmd/vet tests; undocumented for now
+ // This flag declaration is a placeholder:
+ // -vettool is actually parsed by the init function above.
+ cmd.Flag.StringVar(new(string), "vettool", "", "path to vet tool binary")
cmd.Flag.VisitAll(func(f *flag.Flag) {
vetFlagDefn = append(vetFlagDefn, &cmdflag.Defn{
Name: f.Name,
Value: f.Value,
})
})
-}
-// vetFlags processes the command line, splitting it at the first non-flag
-// into the list of flags and list of packages.
-func vetFlags(args []string) (passToVet, packageNames []string) {
+ // Process args.
args = str.StringList(cmdflag.FindGOFLAGS(vetFlagDefn), args)
for i := 0; i < len(args); i++ {
if !strings.HasPrefix(args[i], "-") {
return args[:i], args[i:]
}
- f, value, extraWord := cmdflag.Parse(cmd, vetFlagDefn, args, i)
+ f, value, extraWord := cmdflag.Parse("vet", usage, vetFlagDefn, args, i)
if f == nil {
fmt.Fprintf(os.Stderr, "vet: flag %q not defined\n", args[i])
fmt.Fprintf(os.Stderr, "Run \"go help vet\" for more information\n")
@@ -117,3 +166,21 @@ func vetFlags(args []string) (passToVet, packageNames []string) {
}
return args, nil
}
+
+var vetUsage func()
+
+func init() { vetUsage = usage } // break initialization cycle
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "usage: %s\n", CmdVet.UsageLine)
+ fmt.Fprintf(os.Stderr, "Run 'go help %s' for details.\n", CmdVet.LongName())
+
+ // This part is additional to what (*Command).Usage does:
+ cmd := "go tool vet"
+ if vetTool != "" {
+ cmd = vetTool
+ }
+ fmt.Fprintf(os.Stderr, "Run '%s -help' for the vet tool's flags.\n", cmd)
+
+ os.Exit(2)
+}
diff --git a/libgo/go/cmd/go/internal/web2/web.go b/libgo/go/cmd/go/internal/web2/web.go
index f3900379e17..64934f1d506 100644
--- a/libgo/go/cmd/go/internal/web2/web.go
+++ b/libgo/go/cmd/go/internal/web2/web.go
@@ -7,11 +7,13 @@ package web2
import (
"bytes"
"cmd/go/internal/base"
+ "cmd/go/internal/cfg"
"encoding/json"
"flag"
"fmt"
"io"
"io/ioutil"
+ "log"
"net/http"
"os"
"path/filepath"
@@ -187,10 +189,10 @@ func SetHTTPDoForTesting(do func(*http.Request) (*http.Response, error)) {
}
func Get(url string, options ...Option) error {
- if TraceGET || webstack {
- println("GET", url)
+ if TraceGET || webstack || cfg.BuildV {
+ log.Printf("Fetching %s", url)
if webstack {
- println(string(debug.Stack()))
+ log.Println(string(debug.Stack()))
}
}
diff --git a/libgo/go/cmd/go/internal/work/action.go b/libgo/go/cmd/go/internal/work/action.go
index 82cf228fa44..d0d02117a73 100644
--- a/libgo/go/cmd/go/internal/work/action.go
+++ b/libgo/go/cmd/go/internal/work/action.go
@@ -11,9 +11,9 @@ import (
"bytes"
"container/heap"
"debug/elf"
- "debug/xcoff"
"encoding/json"
"fmt"
+ "internal/xcoff"
"io/ioutil"
"os"
"path/filepath"
diff --git a/libgo/go/cmd/go/internal/work/build.go b/libgo/go/cmd/go/internal/work/build.go
index ed41ce5d073..145b87513a9 100644
--- a/libgo/go/cmd/go/internal/work/build.go
+++ b/libgo/go/cmd/go/internal/work/build.go
@@ -99,7 +99,7 @@ and test commands:
link against shared libraries previously created with
-buildmode=shared.
-mod mode
- module download mode to use: readonly, release, or vendor.
+ module download mode to use: readonly or vendor.
See 'go help modules' for more.
-pkgdir dir
install and load all packages from dir instead of the usual locations.
@@ -398,10 +398,10 @@ func libname(args []string, pkgs []*load.Package) (string, error) {
arg = bp.ImportPath
}
}
- appendName(strings.Replace(arg, "/", "-", -1))
+ appendName(strings.ReplaceAll(arg, "/", "-"))
} else {
for _, pkg := range pkgs {
- appendName(strings.Replace(pkg.ImportPath, "/", "-", -1))
+ appendName(strings.ReplaceAll(pkg.ImportPath, "/", "-"))
}
}
} else if haveNonMeta { // have both meta package and a non-meta one
diff --git a/libgo/go/cmd/go/internal/work/build_test.go b/libgo/go/cmd/go/internal/work/build_test.go
index 010e17ee480..ef95a408ca3 100644
--- a/libgo/go/cmd/go/internal/work/build_test.go
+++ b/libgo/go/cmd/go/internal/work/build_test.go
@@ -227,6 +227,8 @@ func TestRespectSetgidDir(t *testing.T) {
if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
t.Skip("can't set SetGID bit with chmod on iOS")
}
+ case "windows", "plan9", "js":
+ t.Skip("chown/chmod setgid are not supported on Windows, Plan 9, or JS")
}
var b Builder
@@ -245,11 +247,13 @@ func TestRespectSetgidDir(t *testing.T) {
}
defer os.RemoveAll(setgiddir)
- if runtime.GOOS == "freebsd" {
- err = os.Chown(setgiddir, os.Getuid(), os.Getgid())
- if err != nil {
- t.Fatal(err)
- }
+ // BSD mkdir(2) inherits the parent directory group, and other platforms
+ // can inherit the parent directory group via setgid. The test setup (chmod
+ // setgid) will fail if the process does not have the group permission to
+ // the new temporary directory.
+ err = os.Chown(setgiddir, os.Getuid(), os.Getgid())
+ if err != nil {
+ t.Fatal(err)
}
// Change setgiddir's permissions to include the SetGID bit.
diff --git a/libgo/go/cmd/go/internal/work/buildid.go b/libgo/go/cmd/go/internal/work/buildid.go
index fb57e912802..750bc3c6cdb 100644
--- a/libgo/go/cmd/go/internal/work/buildid.go
+++ b/libgo/go/cmd/go/internal/work/buildid.go
@@ -18,7 +18,6 @@ import (
"cmd/go/internal/load"
"cmd/go/internal/str"
"cmd/internal/buildid"
- "cmd/internal/objabi"
)
// Build IDs
@@ -178,7 +177,8 @@ func (b *Builder) toolID(name string) string {
path := base.Tool(name)
desc := "go tool " + name
- // Special case: undocumented -vettool overrides usual vet, for testing vet.
+ // Special case: undocumented -vettool overrides usual vet,
+ // for testing vet or supplying an alternative analysis tool.
if name == "vet" && VetTool != "" {
path = VetTool
desc = VetTool
@@ -207,11 +207,6 @@ func (b *Builder) toolID(name string) string {
id = f[2]
}
- // For the compiler, add any experiments.
- if name == "compile" {
- id += " " + objabi.Expstring()
- }
-
b.id.Lock()
b.toolIDCache[name] = id
b.id.Unlock()
@@ -322,13 +317,16 @@ func assemblerIsGas() bool {
}
}
-// gccgoBuildIDELFFile creates an assembler file that records the
-// action's build ID in an SHF_EXCLUDE section.
-func (b *Builder) gccgoBuildIDELFFile(a *Action) (string, error) {
+// gccgoBuildIDFile creates an assembler file that records the
+// action's build ID in an SHF_EXCLUDE section for ELF files or
+// in a CSECT in XCOFF files.
+func (b *Builder) gccgoBuildIDFile(a *Action) (string, error) {
sfile := a.Objdir + "_buildid.s"
var buf bytes.Buffer
- if cfg.Goos != "solaris" || assemblerIsGas() {
+ if cfg.Goos == "aix" {
+ fmt.Fprintf(&buf, "\t.csect .go.buildid[XO]\n")
+ } else if cfg.Goos != "solaris" || assemblerIsGas() {
fmt.Fprintf(&buf, "\t"+`.section .go.buildid,"e"`+"\n")
} else if cfg.Goarch == "sparc" || cfg.Goarch == "sparc64" {
fmt.Fprintf(&buf, "\t"+`.section ".go.buildid",#exclude`+"\n")
@@ -347,7 +345,7 @@ func (b *Builder) gccgoBuildIDELFFile(a *Action) (string, error) {
fmt.Fprintf(&buf, "%#02x", a.buildID[i])
}
fmt.Fprintf(&buf, "\n")
- if cfg.Goos != "solaris" {
+ if cfg.Goos != "solaris" && cfg.Goos != "aix" {
secType := "@progbits"
if cfg.Goarch == "arm" {
secType = "%progbits"
@@ -372,43 +370,6 @@ func (b *Builder) gccgoBuildIDELFFile(a *Action) (string, error) {
return sfile, nil
}
-// gccgoBuildIDXCOFFFile creates an assembler file that records the
-// action's build ID in a CSECT (AIX linker deletes CSECTs that are
-// not referenced in the output file).
-func (b *Builder) gccgoBuildIDXCOFFFile(a *Action) (string, error) {
- sfile := a.Objdir + "_buildid.s"
-
- var buf bytes.Buffer
- fmt.Fprintf(&buf, "\t.csect .go.buildid[XO]\n")
- fmt.Fprintf(&buf, "\t.byte ")
- for i := 0; i < len(a.buildID); i++ {
- if i > 0 {
- if i%8 == 0 {
- fmt.Fprintf(&buf, "\n\t.byte ")
- } else {
- fmt.Fprintf(&buf, ",")
- }
- }
- fmt.Fprintf(&buf, "%#02x", a.buildID[i])
- }
- fmt.Fprintf(&buf, "\n")
-
- if cfg.BuildN || cfg.BuildX {
- for _, line := range bytes.Split(buf.Bytes(), []byte("\n")) {
- b.Showcmd("", "echo '%s' >> %s", line, sfile)
- }
- if cfg.BuildN {
- return sfile, nil
- }
- }
-
- if err := ioutil.WriteFile(sfile, buf.Bytes(), 0666); err != nil {
- return "", err
- }
-
- return sfile, nil
-}
-
// buildID returns the build ID found in the given file.
// If no build ID is found, buildID returns the content hash of the file.
func (b *Builder) buildID(file string) string {
diff --git a/libgo/go/cmd/go/internal/work/exec.go b/libgo/go/cmd/go/internal/work/exec.go
index 8aba293dd34..a4feb1d0058 100644
--- a/libgo/go/cmd/go/internal/work/exec.go
+++ b/libgo/go/cmd/go/internal/work/exec.go
@@ -377,7 +377,7 @@ func (b *Builder) build(a *Action) (err error) {
if b.NeedExport {
p.Export = a.built
}
- if need&needCompiledGoFiles != 0 && b.loadCachedGoFiles(a) {
+ if need&needCompiledGoFiles != 0 && b.loadCachedSrcFiles(a) {
need &^= needCompiledGoFiles
}
// Otherwise, we need to write files to a.Objdir (needVet, needCgoHdr).
@@ -386,6 +386,13 @@ func (b *Builder) build(a *Action) (err error) {
cached = true
a.output = []byte{} // start saving output in case we miss any cache results
}
+
+ // Source files might be cached, even if the full action is not
+ // (e.g., go list -compiled -find).
+ if !cached && need&needCompiledGoFiles != 0 && b.loadCachedSrcFiles(a) {
+ need &^= needCompiledGoFiles
+ }
+
if need == 0 {
return nil
}
@@ -434,10 +441,6 @@ func (b *Builder) build(a *Action) (err error) {
return fmt.Errorf("missing or invalid binary-only package; expected file %q", a.Package.Target)
}
- if p.Module != nil && !allowedVersion(p.Module.GoVersion) {
- return fmt.Errorf("module requires Go %s", p.Module.GoVersion)
- }
-
if err := b.Mkdir(a.Objdir); err != nil {
return err
}
@@ -579,7 +582,13 @@ func (b *Builder) build(a *Action) (err error) {
b.cacheCgoHdr(a)
}
}
- b.cacheGofiles(a, gofiles)
+
+ var srcfiles []string // .go and non-.go
+ srcfiles = append(srcfiles, gofiles...)
+ srcfiles = append(srcfiles, sfiles...)
+ srcfiles = append(srcfiles, cfiles...)
+ srcfiles = append(srcfiles, cxxfiles...)
+ b.cacheSrcFiles(a, srcfiles)
// Running cgo generated the cgo header.
need &^= needCgoHdr
@@ -591,11 +600,11 @@ func (b *Builder) build(a *Action) (err error) {
// Prepare Go vet config if needed.
if need&needVet != 0 {
- buildVetConfig(a, gofiles)
+ buildVetConfig(a, srcfiles)
need &^= needVet
}
if need&needCompiledGoFiles != 0 {
- if !b.loadCachedGoFiles(a) {
+ if !b.loadCachedSrcFiles(a) {
return fmt.Errorf("failed to cache compiled Go files")
}
need &^= needCompiledGoFiles
@@ -605,6 +614,12 @@ func (b *Builder) build(a *Action) (err error) {
return nil
}
+ // Collect symbol ABI requirements from assembly.
+ symabis, err := BuildToolchain.symabis(b, a, sfiles)
+ if err != nil {
+ return err
+ }
+
// Prepare Go import config.
// We start it off with a comment so it can't be empty, so icfg.Bytes() below is never nil.
// It should never be empty anyway, but there have been bugs in the past that resulted
@@ -638,14 +653,21 @@ func (b *Builder) build(a *Action) (err error) {
// Compile Go.
objpkg := objdir + "_pkg_.a"
- ofile, out, err := BuildToolchain.gc(b, a, objpkg, icfg.Bytes(), len(sfiles) > 0, gofiles)
+ ofile, out, err := BuildToolchain.gc(b, a, objpkg, icfg.Bytes(), symabis, len(sfiles) > 0, gofiles)
if len(out) > 0 {
- b.showOutput(a, a.Package.Dir, a.Package.Desc(), b.processOutput(out))
+ output := b.processOutput(out)
+ if p.Module != nil && !allowedVersion(p.Module.GoVersion) {
+ output += "note: module requires Go " + p.Module.GoVersion
+ }
+ b.showOutput(a, a.Package.Dir, a.Package.Desc(), output)
if err != nil {
return errPrintedOutput
}
}
if err != nil {
+ if p.Module != nil && !allowedVersion(p.Module.GoVersion) {
+ b.showOutput(a, a.Package.Dir, a.Package.Desc(), "note: module requires Go "+p.Module.GoVersion)
+ }
return err
}
if ofile != objpkg {
@@ -701,18 +723,8 @@ func (b *Builder) build(a *Action) (err error) {
// This is read by readGccgoArchive in cmd/internal/buildid/buildid.go.
if a.buildID != "" && cfg.BuildToolchainName == "gccgo" {
switch cfg.Goos {
- case "android", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
- asmfile, err := b.gccgoBuildIDELFFile(a)
- if err != nil {
- return err
- }
- ofiles, err := BuildToolchain.asm(b, a, []string{asmfile})
- if err != nil {
- return err
- }
- objects = append(objects, ofiles...)
- case "aix":
- asmfile, err := b.gccgoBuildIDXCOFFFile(a)
+ case "aix", "android", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
+ asmfile, err := b.gccgoBuildIDFile(a)
if err != nil {
return err
}
@@ -797,13 +809,13 @@ func (b *Builder) loadCachedCgoHdr(a *Action) bool {
return err == nil
}
-func (b *Builder) cacheGofiles(a *Action, gofiles []string) {
+func (b *Builder) cacheSrcFiles(a *Action, srcfiles []string) {
c := cache.Default()
if c == nil {
return
}
var buf bytes.Buffer
- for _, file := range gofiles {
+ for _, file := range srcfiles {
if !strings.HasPrefix(file, a.Objdir) {
// not generated
buf.WriteString("./")
@@ -818,7 +830,7 @@ func (b *Builder) cacheGofiles(a *Action, gofiles []string) {
return
}
}
- c.PutBytes(cache.Subkey(a.actionID, "gofiles"), buf.Bytes())
+ c.PutBytes(cache.Subkey(a.actionID, "srcfiles"), buf.Bytes())
}
func (b *Builder) loadCachedVet(a *Action) bool {
@@ -826,34 +838,34 @@ func (b *Builder) loadCachedVet(a *Action) bool {
if c == nil {
return false
}
- list, _, err := c.GetBytes(cache.Subkey(a.actionID, "gofiles"))
+ list, _, err := c.GetBytes(cache.Subkey(a.actionID, "srcfiles"))
if err != nil {
return false
}
- var gofiles []string
+ var srcfiles []string
for _, name := range strings.Split(string(list), "\n") {
if name == "" { // end of list
continue
}
if strings.HasPrefix(name, "./") {
- gofiles = append(gofiles, name[2:])
+ srcfiles = append(srcfiles, name[2:])
continue
}
if err := b.loadCachedObjdirFile(a, c, name); err != nil {
return false
}
- gofiles = append(gofiles, a.Objdir+name)
+ srcfiles = append(srcfiles, a.Objdir+name)
}
- buildVetConfig(a, gofiles)
+ buildVetConfig(a, srcfiles)
return true
}
-func (b *Builder) loadCachedGoFiles(a *Action) bool {
+func (b *Builder) loadCachedSrcFiles(a *Action) bool {
c := cache.Default()
if c == nil {
return false
}
- list, _, err := c.GetBytes(cache.Subkey(a.actionID, "gofiles"))
+ list, _, err := c.GetBytes(cache.Subkey(a.actionID, "srcfiles"))
if err != nil {
return false
}
@@ -878,10 +890,12 @@ func (b *Builder) loadCachedGoFiles(a *Action) bool {
// vetConfig is the configuration passed to vet describing a single package.
type vetConfig struct {
+ ID string // package ID (example: "fmt [fmt.test]")
Compiler string // compiler name (gc, gccgo)
Dir string // directory containing package
ImportPath string // canonical import path ("package path")
GoFiles []string // absolute paths to package source files
+ NonGoFiles []string // absolute paths to package non-Go files
ImportMap map[string]string // map import path in source code to package path
PackageFile map[string]string // map package path to .a file with export data
@@ -893,15 +907,28 @@ type vetConfig struct {
SucceedOnTypecheckFailure bool // awful hack; see #18395 and below
}
-func buildVetConfig(a *Action, gofiles []string) {
+func buildVetConfig(a *Action, srcfiles []string) {
+ // Classify files based on .go extension.
+ // srcfiles does not include raw cgo files.
+ var gofiles, nongofiles []string
+ for _, name := range srcfiles {
+ if strings.HasSuffix(name, ".go") {
+ gofiles = append(gofiles, name)
+ } else {
+ nongofiles = append(nongofiles, name)
+ }
+ }
+
// Pass list of absolute paths to vet,
// so that vet's error messages will use absolute paths,
// so that we can reformat them relative to the directory
// in which the go command is invoked.
vcfg := &vetConfig{
+ ID: a.Package.ImportPath,
Compiler: cfg.BuildToolchainName,
Dir: a.Package.Dir,
GoFiles: mkAbsFiles(a.Package.Dir, gofiles),
+ NonGoFiles: mkAbsFiles(a.Package.Dir, nongofiles),
ImportPath: a.Package.ImportPath,
ImportMap: make(map[string]string),
PackageFile: make(map[string]string),
@@ -998,6 +1025,8 @@ func (b *Builder) vet(a *Action) error {
}
}
+ // TODO(adonovan): delete this when we use the new vet printf checker.
+ // https://github.com/golang/go/issues/28756
if vcfg.ImportMap["fmt"] == "" {
a1 := a.Deps[1]
vcfg.ImportMap["fmt"] = "fmt"
@@ -1621,6 +1650,25 @@ func (b *Builder) writeFile(file string, text []byte) error {
return ioutil.WriteFile(file, text, 0666)
}
+// appendFile appends the text to file.
+func (b *Builder) appendFile(file string, text []byte) error {
+ if cfg.BuildN || cfg.BuildX {
+ b.Showcmd("", "cat >>%s << 'EOF' # internal\n%sEOF", file, text)
+ }
+ if cfg.BuildN {
+ return nil
+ }
+ f, err := os.OpenFile(file, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ if _, err = f.Write(text); err != nil {
+ return err
+ }
+ return f.Close()
+}
+
// Install the cgo export header file, if there is one.
func (b *Builder) installHeader(a *Action) error {
src := a.Objdir + "_cgo_install.h"
@@ -1671,8 +1719,8 @@ var objectMagic = [][]byte{
{0x00, 0x00, 0x8a, 0x97}, // Plan 9 amd64
{0x00, 0x00, 0x06, 0x47}, // Plan 9 arm
{0x00, 0x61, 0x73, 0x6D}, // WASM
- {0x01, 0xDF}, // XCOFF32
- {0x01, 0xF7}, // XCOFF64
+ {0x01, 0xDF}, // XCOFF 32bit
+ {0x01, 0xF7}, // XCOFF 64bit
}
func isObject(s string) bool {
@@ -1720,14 +1768,14 @@ func (b *Builder) fmtcmd(dir string, format string, args ...interface{}) string
if dir[len(dir)-1] == filepath.Separator {
dot += string(filepath.Separator)
}
- cmd = strings.Replace(" "+cmd, " "+dir, dot, -1)[1:]
+ cmd = strings.ReplaceAll(" "+cmd, " "+dir, dot)[1:]
if b.scriptDir != dir {
b.scriptDir = dir
cmd = "cd " + dir + "\n" + cmd
}
}
if b.WorkDir != "" {
- cmd = strings.Replace(cmd, b.WorkDir, "$WORK", -1)
+ cmd = strings.ReplaceAll(cmd, b.WorkDir, "$WORK")
}
return cmd
}
@@ -1769,10 +1817,10 @@ func (b *Builder) showOutput(a *Action, dir, desc, out string) {
prefix := "# " + desc
suffix := "\n" + out
if reldir := base.ShortPath(dir); reldir != dir {
- suffix = strings.Replace(suffix, " "+dir, " "+reldir, -1)
- suffix = strings.Replace(suffix, "\n"+dir, "\n"+reldir, -1)
+ suffix = strings.ReplaceAll(suffix, " "+dir, " "+reldir)
+ suffix = strings.ReplaceAll(suffix, "\n"+dir, "\n"+reldir)
}
- suffix = strings.Replace(suffix, " "+b.WorkDir, " $WORK", -1)
+ suffix = strings.ReplaceAll(suffix, " "+b.WorkDir, " $WORK")
if a != nil && a.output != nil {
a.output = append(a.output, prefix...)
@@ -1976,13 +2024,18 @@ func mkAbs(dir, f string) string {
type toolchain interface {
// gc runs the compiler in a specific directory on a set of files
// and returns the name of the generated output file.
- gc(b *Builder, a *Action, archive string, importcfg []byte, asmhdr bool, gofiles []string) (ofile string, out []byte, err error)
+ //
+ // TODO: This argument list is long. Consider putting it in a struct.
+ gc(b *Builder, a *Action, archive string, importcfg []byte, symabis string, asmhdr bool, gofiles []string) (ofile string, out []byte, err error)
// cc runs the toolchain's C compiler in a directory on a C file
// to produce an output file.
cc(b *Builder, a *Action, ofile, cfile string) error
// asm runs the assembler in a specific directory on specific files
// and returns a list of named output files.
asm(b *Builder, a *Action, sfiles []string) ([]string, error)
+ // symabis scans the symbol ABIs from sfiles and returns the
+ // path to the output symbol ABIs file, or "" if none.
+ symabis(b *Builder, a *Action, sfiles []string) (string, error)
// pack runs the archive packer in a specific directory to create
// an archive from a set of object files.
// typically it is run in the object directory.
@@ -2013,7 +2066,7 @@ func (noToolchain) linker() string {
return ""
}
-func (noToolchain) gc(b *Builder, a *Action, archive string, importcfg []byte, asmhdr bool, gofiles []string) (ofile string, out []byte, err error) {
+func (noToolchain) gc(b *Builder, a *Action, archive string, importcfg []byte, symabis string, asmhdr bool, gofiles []string) (ofile string, out []byte, err error) {
return "", nil, noCompiler()
}
@@ -2021,6 +2074,10 @@ func (noToolchain) asm(b *Builder, a *Action, sfiles []string) ([]string, error)
return nil, noCompiler()
}
+func (noToolchain) symabis(b *Builder, a *Action, sfiles []string) (string, error) {
+ return "", noCompiler()
+}
+
func (noToolchain) pack(b *Builder, a *Action, afile string, ofiles []string) error {
return noCompiler()
}
@@ -2092,14 +2149,37 @@ func (b *Builder) ccompile(a *Action, p *load.Package, outfile string, flags []s
}
// gccld runs the gcc linker to create an executable from a set of object files.
-func (b *Builder) gccld(p *load.Package, objdir, out string, flags []string, objs []string) error {
+func (b *Builder) gccld(p *load.Package, objdir, outfile string, flags []string, objs []string) error {
var cmd []string
if len(p.CXXFiles) > 0 || len(p.SwigCXXFiles) > 0 {
cmd = b.GxxCmd(p.Dir, objdir)
} else {
cmd = b.GccCmd(p.Dir, objdir)
}
- return b.run(nil, p.Dir, p.ImportPath, b.cCompilerEnv(), cmd, "-o", out, objs, flags)
+
+ cmdargs := []interface{}{cmd, "-o", outfile, objs, flags}
+ dir := p.Dir
+ out, err := b.runOut(dir, b.cCompilerEnv(), cmdargs...)
+ if len(out) > 0 {
+ // Filter out useless linker warnings caused by bugs outside Go.
+ // See also cmd/link/internal/ld's hostlink method.
+ var save [][]byte
+ for _, line := range bytes.SplitAfter(out, []byte("\n")) {
+ // golang.org/issue/26073 - Apple Xcode bug
+ if bytes.Contains(line, []byte("ld: warning: text-based stub file")) {
+ continue
+ }
+ save = append(save, line)
+ }
+ out = bytes.Join(save, nil)
+ if len(out) > 0 {
+ b.showOutput(nil, dir, p.ImportPath, b.processOutput(out))
+ if err != nil {
+ err = errPrintedOutput
+ }
+ }
+ }
+ return err
}
// Grab these before main helpfully overwrites them.
@@ -2686,7 +2766,7 @@ func (b *Builder) swigDoIntSize(objdir string) (intsize string, err error) {
p := load.GoFilesPackage(srcs)
- if _, _, e := BuildToolchain.gc(b, &Action{Mode: "swigDoIntSize", Package: p, Objdir: objdir}, "", nil, false, srcs); e != nil {
+ if _, _, e := BuildToolchain.gc(b, &Action{Mode: "swigDoIntSize", Package: p, Objdir: objdir}, "", nil, "", false, srcs); e != nil {
return "32", nil
}
return "64", nil
@@ -2884,7 +2964,7 @@ func useResponseFile(path string, argLen int) bool {
}
// On the Go build system, use response files about 10% of the
- // time, just to excercise this codepath.
+ // time, just to exercise this codepath.
isBuilder := os.Getenv("GO_BUILDER_NAME") != ""
if isBuilder && rand.Intn(10) == 0 {
return true
diff --git a/libgo/go/cmd/go/internal/work/gc.go b/libgo/go/cmd/go/internal/work/gc.go
index 6e5333ccbc4..3d09f69fcc3 100644
--- a/libgo/go/cmd/go/internal/work/gc.go
+++ b/libgo/go/cmd/go/internal/work/gc.go
@@ -36,7 +36,7 @@ func (gcToolchain) linker() string {
return base.Tool("link")
}
-func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg []byte, asmhdr bool, gofiles []string) (ofile string, output []byte, err error) {
+func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg []byte, symabis string, asmhdr bool, gofiles []string) (ofile string, output []byte, err error) {
p := a.Package
objdir := a.Objdir
if archive != "" {
@@ -53,6 +53,9 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg []byte, a
pkgpath = "main"
}
gcargs := []string{"-p", pkgpath}
+ if p.Module != nil && p.Module.GoVersion != "" && allowedVersion(p.Module.GoVersion) {
+ gcargs = append(gcargs, "-lang=go"+p.Module.GoVersion)
+ }
if p.Standard {
gcargs = append(gcargs, "-std")
}
@@ -95,6 +98,9 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg []byte, a
if strings.HasPrefix(runtimeVersion, "go1") && !strings.Contains(os.Args[0], "go_bootstrap") {
gcargs = append(gcargs, "-goversion", runtimeVersion)
}
+ if symabis != "" {
+ gcargs = append(gcargs, "-symabis", symabis)
+ }
gcflags := str.StringList(forcedGcflags, p.Internal.Gcflags)
if compilingRuntime {
@@ -168,7 +174,7 @@ CheckFlags:
}
// TODO: Test and delete these conditions.
- if objabi.Fieldtrack_enabled != 0 || objabi.Preemptibleloops_enabled != 0 || objabi.Clobberdead_enabled != 0 {
+ if objabi.Fieldtrack_enabled != 0 || objabi.Preemptibleloops_enabled != 0 {
canDashC = false
}
@@ -215,8 +221,7 @@ func trimDir(dir string) string {
return dir
}
-func (gcToolchain) asm(b *Builder, a *Action, sfiles []string) ([]string, error) {
- p := a.Package
+func asmArgs(a *Action, p *load.Package) []interface{} {
// Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files.
inc := filepath.Join(cfg.GOROOT, "pkg", "include")
args := []interface{}{cfg.BuildToolexec, base.Tool("asm"), "-trimpath", trimDir(a.Objdir), "-I", a.Objdir, "-I", inc, "-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch, forcedAsmflags, p.Internal.Asmflags}
@@ -238,6 +243,13 @@ func (gcToolchain) asm(b *Builder, a *Action, sfiles []string) ([]string, error)
args = append(args, "-D", "GOMIPS64_"+cfg.GOMIPS64)
}
+ return args
+}
+
+func (gcToolchain) asm(b *Builder, a *Action, sfiles []string) ([]string, error) {
+ p := a.Package
+ args := asmArgs(a, p)
+
var ofiles []string
for _, sfile := range sfiles {
ofile := a.Objdir + sfile[:len(sfile)-len(".s")] + ".o"
@@ -250,6 +262,88 @@ func (gcToolchain) asm(b *Builder, a *Action, sfiles []string) ([]string, error)
return ofiles, nil
}
+func (gcToolchain) symabis(b *Builder, a *Action, sfiles []string) (string, error) {
+ mkSymabis := func(p *load.Package, sfiles []string, path string) error {
+ args := asmArgs(a, p)
+ args = append(args, "-gensymabis", "-o", path)
+ for _, sfile := range sfiles {
+ if p.ImportPath == "runtime/cgo" && strings.HasPrefix(sfile, "gcc_") {
+ continue
+ }
+ args = append(args, mkAbs(p.Dir, sfile))
+ }
+
+ // Supply an empty go_asm.h as if the compiler had been run.
+ // -gensymabis parsing is lax enough that we don't need the
+ // actual definitions that would appear in go_asm.h.
+ if err := b.writeFile(a.Objdir+"go_asm.h", nil); err != nil {
+ return err
+ }
+
+ return b.run(a, p.Dir, p.ImportPath, nil, args...)
+ }
+
+ var symabis string // Only set if we actually create the file
+ p := a.Package
+ if len(sfiles) != 0 {
+ symabis = a.Objdir + "symabis"
+ if err := mkSymabis(p, sfiles, symabis); err != nil {
+ return "", err
+ }
+ }
+
+ // Gather known cross-package references from assembly code.
+ var otherPkgs []string
+ if p.ImportPath == "runtime" {
+ // Assembly in the following packages references
+ // symbols in runtime.
+ otherPkgs = []string{"syscall", "internal/syscall/unix", "runtime/cgo"}
+ } else if p.ImportPath == "runtime/internal/atomic" {
+ // sync/atomic is an assembly wrapper around
+ // runtime/internal/atomic.
+ otherPkgs = []string{"sync/atomic"}
+ }
+ for _, p2name := range otherPkgs {
+ p2 := load.LoadPackage(p2name, &load.ImportStack{})
+ if len(p2.SFiles) == 0 {
+ continue
+ }
+
+ symabis2 := a.Objdir + "symabis2"
+ if err := mkSymabis(p2, p2.SFiles, symabis2); err != nil {
+ return "", err
+ }
+
+ // Filter out just the symbol refs and append them to
+ // the symabis file.
+ if cfg.BuildN {
+ // -x will print the lines from symabis2 that are actually appended
+ // to symabis. With -n, we don't know what those lines will be.
+ b.Showcmd("", `grep '^ref' <%s | grep -v '^ref\s*""\.' >>%s`, symabis2, a.Objdir+"symabis")
+ continue
+ }
+ abis2, err := ioutil.ReadFile(symabis2)
+ if err != nil {
+ return "", err
+ }
+ var refs bytes.Buffer
+ for _, line := range strings.Split(string(abis2), "\n") {
+ fs := strings.Fields(line)
+ if len(fs) >= 2 && fs[0] == "ref" && !strings.HasPrefix(fs[1], `"".`) {
+ fmt.Fprintf(&refs, "%s\n", line)
+ }
+ }
+ if refs.Len() != 0 {
+ symabis = a.Objdir + "symabis"
+ if err := b.appendFile(symabis, refs.Bytes()); err != nil {
+ return "", err
+ }
+ }
+ }
+
+ return symabis, nil
+}
+
// toolVerify checks that the command line args writes the same output file
// if run using newTool instead.
// Unused now but kept around for future use.
diff --git a/libgo/go/cmd/go/internal/work/gccgo.go b/libgo/go/cmd/go/internal/work/gccgo.go
index 7255748b5c3..82da5912b2d 100644
--- a/libgo/go/cmd/go/internal/work/gccgo.go
+++ b/libgo/go/cmd/go/internal/work/gccgo.go
@@ -43,6 +43,14 @@ func (gccgoToolchain) linker() string {
return GccgoBin
}
+func (gccgoToolchain) ar() string {
+ ar := os.Getenv("AR")
+ if ar == "" {
+ ar = "ar"
+ }
+ return ar
+}
+
func checkGccgoBin() {
if gccgoErr == nil {
return
@@ -51,7 +59,7 @@ func checkGccgoBin() {
os.Exit(2)
}
-func (tools gccgoToolchain) gc(b *Builder, a *Action, archive string, importcfg []byte, asmhdr bool, gofiles []string) (ofile string, output []byte, err error) {
+func (tools gccgoToolchain) gc(b *Builder, a *Action, archive string, importcfg []byte, symabis string, asmhdr bool, gofiles []string) (ofile string, output []byte, err error) {
p := a.Package
objdir := a.Objdir
out := "_go_.o"
@@ -174,6 +182,10 @@ func (tools gccgoToolchain) asm(b *Builder, a *Action, sfiles []string) ([]strin
return ofiles, nil
}
+func (gccgoToolchain) symabis(b *Builder, a *Action, sfiles []string) (string, error) {
+ return "", nil
+}
+
func gccgoArchive(basedir, imp string) string {
end := filepath.FromSlash(imp + ".a")
afile := filepath.Join(basedir, end)
@@ -181,26 +193,22 @@ func gccgoArchive(basedir, imp string) string {
return filepath.Join(filepath.Dir(afile), "lib"+filepath.Base(afile))
}
-func (gccgoToolchain) pack(b *Builder, a *Action, afile string, ofiles []string) error {
+func (tools gccgoToolchain) pack(b *Builder, a *Action, afile string, ofiles []string) error {
p := a.Package
objdir := a.Objdir
var absOfiles []string
for _, f := range ofiles {
absOfiles = append(absOfiles, mkAbs(objdir, f))
}
- absAfile := mkAbs(objdir, afile)
- // Try with D modifier first, then without if that fails.
- if cfg.Goos == "aix" || b.run(a, p.Dir, p.ImportPath, nil, "ar", "rcD", absAfile, absOfiles) != nil {
- var arArgs []string
- if cfg.Goos == "aix" && cfg.Goarch == "ppc64" {
- // AIX puts both 32-bit and 64-bit objects in the same archive.
- // Tell the AIX "ar" command to only care about 64-bit objects.
- // AIX "ar" command does not know D option.
- arArgs = append(arArgs, "-X64")
- }
- return b.run(a, p.Dir, p.ImportPath, nil, "ar", arArgs, "rc", absAfile, absOfiles)
+ var arArgs []string
+ if cfg.Goos == "aix" && cfg.Goarch == "ppc64" {
+ // AIX puts both 32-bit and 64-bit objects in the same archive.
+ // Tell the AIX "ar" command to only care about 64-bit objects.
+ // AIX "ar" command does not know D option.
+ arArgs = []string{"-X64"}
}
- return nil
+
+ return b.run(a, p.Dir, p.ImportPath, nil, tools.ar(), arArgs, "rc", mkAbs(objdir, afile), absOfiles)
}
func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string, allactions []*Action, buildmode, desc string) error {
@@ -281,11 +289,11 @@ func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string
b.Showcmd("", "ar d %s _cgo_flags", newArchive)
return "", nil
}
- err := b.run(root, root.Objdir, desc, nil, "ar", "x", newArchive, "_cgo_flags")
+ err := b.run(root, root.Objdir, desc, nil, tools.ar(), "x", newArchive, "_cgo_flags")
if err != nil {
return "", err
}
- err = b.run(root, ".", desc, nil, "ar", "d", newArchive, "_cgo_flags")
+ err = b.run(root, ".", desc, nil, tools.ar(), "d", newArchive, "_cgo_flags")
if err != nil {
return "", err
}
@@ -393,7 +401,6 @@ func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string
if root.Package != nil {
ldflags = append(ldflags, root.Package.CgoLDFLAGS...)
}
-
if cfg.Goos != "aix" {
ldflags = str.StringList("-Wl,-(", ldflags, "-Wl,-)")
}
@@ -505,7 +512,7 @@ func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string
switch buildmode {
case "c-archive":
- if err := b.run(root, ".", desc, nil, "ar", "rc", realOut, out); err != nil {
+ if err := b.run(root, ".", desc, nil, tools.ar(), "rc", realOut, out); err != nil {
return err
}
}
diff --git a/libgo/go/cmd/go/internal/work/init.go b/libgo/go/cmd/go/internal/work/init.go
index 56f1ff229cb..693a53e9ab7 100644
--- a/libgo/go/cmd/go/internal/work/init.go
+++ b/libgo/go/cmd/go/internal/work/init.go
@@ -10,6 +10,7 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
+ "cmd/internal/sys"
"flag"
"fmt"
"os"
@@ -42,18 +43,14 @@ func instrumentInit() {
fmt.Fprintf(os.Stderr, "go %s: may not use -race and -msan simultaneously\n", flag.Args()[0])
os.Exit(2)
}
- if cfg.BuildMSan && (cfg.Goos != "linux" || cfg.Goarch != "amd64" && cfg.Goarch != "arm64") {
+ if cfg.BuildMSan && !sys.MSanSupported(cfg.Goos, cfg.Goarch) {
fmt.Fprintf(os.Stderr, "-msan is not supported on %s/%s\n", cfg.Goos, cfg.Goarch)
os.Exit(2)
}
if cfg.BuildRace {
- platform := cfg.Goos + "/" + cfg.Goarch
- switch platform {
- default:
- fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, linux/ppc64le, freebsd/amd64, netbsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0])
+ if !sys.RaceDetectorSupported(cfg.Goos, cfg.Goarch) {
+ fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, linux/ppc64le, linux/arm64, freebsd/amd64, netbsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0])
os.Exit(2)
- case "linux/amd64", "linux/ppc64le", "freebsd/amd64", "netbsd/amd64", "darwin/amd64", "windows/amd64":
- // race supported on these platforms
}
}
mode := "race"
diff --git a/libgo/go/cmd/go/internal/work/security.go b/libgo/go/cmd/go/internal/work/security.go
index 2132c5f3e15..1a401b8981e 100644
--- a/libgo/go/cmd/go/internal/work/security.go
+++ b/libgo/go/cmd/go/internal/work/security.go
@@ -89,7 +89,9 @@ var validCompilerFlags = []*regexp.Regexp{
re(`-m32`),
re(`-m64`),
re(`-m(abi|arch|cpu|fpu|tune)=([^@\-].*)`),
+ re(`-m(no-)?v?aes`),
re(`-marm`),
+ re(`-m(no-)?avx[0-9a-z]*`),
re(`-mfloat-abi=([^@\-].*)`),
re(`-mfpmath=[0-9a-z,+]*`),
re(`-m(no-)?avx[0-9a-z.]*`),
@@ -100,6 +102,7 @@ var validCompilerFlags = []*regexp.Regexp{
re(`-miphoneos-version-min=(.+)`),
re(`-mnop-fun-dllimport`),
re(`-m(no-)?sse[0-9.]*`),
+ re(`-m(no-)?ssse3`),
re(`-mthumb(-interwork)?`),
re(`-mthreads`),
re(`-mwindows`),
diff --git a/libgo/go/cmd/go/main.go b/libgo/go/cmd/go/main.go
index 14b435295ec..d986f5508d9 100644
--- a/libgo/go/cmd/go/main.go
+++ b/libgo/go/cmd/go/main.go
@@ -93,9 +93,18 @@ func main() {
*get.CmdGet = *modget.CmdGet
}
+ if args[0] == "get" || args[0] == "help" {
+ // Replace get with module-aware get if appropriate.
+ // Note that if MustUseModules is true, this happened already above,
+ // but no harm in doing it again.
+ if modload.Init(); modload.Enabled() {
+ *get.CmdGet = *modget.CmdGet
+ }
+ }
+
cfg.CmdName = args[0] // for error messages
if args[0] == "help" {
- help.Help(args[1:])
+ help.Help(os.Stdout, args[1:])
return
}
@@ -145,10 +154,10 @@ func main() {
flag = flag[:i]
}
switch flag {
- case "-sync":
- fmt.Fprintf(os.Stderr, "go: go mod -sync is now go mod tidy\n")
+ case "-sync", "-fix":
+ fmt.Fprintf(os.Stderr, "go: go mod %s is now go mod tidy\n", flag)
os.Exit(2)
- case "-init", "-fix", "-graph", "-vendor", "-verify":
+ case "-init", "-graph", "-vendor", "-verify":
fmt.Fprintf(os.Stderr, "go: go mod %s is now go mod %s\n", flag, flag[1:])
os.Exit(2)
case "-fmt", "-json", "-module", "-require", "-droprequire", "-replace", "-dropreplace", "-exclude", "-dropexclude":
@@ -164,15 +173,6 @@ func main() {
os.Exit(2)
}
- if args[0] == "get" {
- // Replace get with module-aware get if appropriate.
- // Note that if MustUseModules is true, this happened already above,
- // but no harm in doing it again.
- if modload.Init(); modload.Enabled() {
- *get.CmdGet = *modget.CmdGet
- }
- }
-
// Set environment (GOOS, GOARCH, etc) explicitly.
// In theory all the commands we invoke should have
// the same default computation of these as we do,
@@ -202,7 +202,7 @@ BigCmdLoop:
}
if args[0] == "help" {
// Accept 'go mod help' and 'go mod help foo' for 'go help mod' and 'go help mod foo'.
- help.Help(append(strings.Split(cfg.CmdName, " "), args[1:]...))
+ help.Help(os.Stdout, append(strings.Split(cfg.CmdName, " "), args[1:]...))
return
}
cfg.CmdName += " " + args[0]
@@ -238,10 +238,6 @@ func init() {
}
func mainUsage() {
- // special case "go test -h"
- if len(os.Args) > 1 && os.Args[1] == "test" {
- test.Usage()
- }
help.PrintUsage(os.Stderr, base.Go)
os.Exit(2)
}
diff --git a/libgo/go/cmd/go/proxy_test.go b/libgo/go/cmd/go/proxy_test.go
index 212e5aa08f7..830cea029b7 100644
--- a/libgo/go/cmd/go/proxy_test.go
+++ b/libgo/go/cmd/go/proxy_test.go
@@ -78,7 +78,7 @@ func readModList() {
if i < 0 {
continue
}
- encPath := strings.Replace(name[:i], "_", "/", -1)
+ encPath := strings.ReplaceAll(name[:i], "_", "/")
path, err := module.DecodePath(encPath)
if err != nil {
fmt.Fprintf(os.Stderr, "go proxy_test: %v\n", err)
@@ -197,7 +197,13 @@ func proxyHandler(w http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(f.Name, ".") {
continue
}
- zf, err := z.Create(path + "@" + vers + "/" + f.Name)
+ var zipName string
+ if strings.HasPrefix(f.Name, "/") {
+ zipName = f.Name[1:]
+ } else {
+ zipName = path + "@" + vers + "/" + f.Name
+ }
+ zf, err := z.Create(zipName)
if err != nil {
return cached{nil, err}
}
@@ -256,7 +262,7 @@ func readArchive(path, vers string) *txtar.Archive {
return nil
}
- prefix := strings.Replace(enc, "/", "_", -1)
+ prefix := strings.ReplaceAll(enc, "/", "_")
name := filepath.Join(cmdGoDir, "testdata/mod", prefix+"_"+encVers+".txt")
a := archiveCache.Do(name, func() interface{} {
a, err := txtar.ParseFile(name)
diff --git a/libgo/go/cmd/go/script_test.go b/libgo/go/cmd/go/script_test.go
index 6399faac0f4..f6facfd944f 100644
--- a/libgo/go/cmd/go/script_test.go
+++ b/libgo/go/cmd/go/script_test.go
@@ -9,7 +9,9 @@ package main_test
import (
"bytes"
+ "context"
"fmt"
+ "go/build"
"internal/testenv"
"io/ioutil"
"os"
@@ -25,6 +27,7 @@ import (
"cmd/go/internal/imports"
"cmd/go/internal/par"
"cmd/go/internal/txtar"
+ "cmd/go/internal/work"
)
// TestScript runs the tests in testdata/script/*.txt.
@@ -55,21 +58,28 @@ func TestScript(t *testing.T) {
// A testScript holds execution state for a single test script.
type testScript struct {
- t *testing.T
- workdir string // temporary work dir ($WORK)
- log bytes.Buffer // test execution log (printed at end of test)
- mark int // offset of next log truncation
- cd string // current directory during test execution; initially $WORK/gopath/src
- name string // short name of test ("foo")
- file string // full file name ("testdata/script/foo.txt")
- lineno int // line number currently executing
- line string // line currently executing
- env []string // environment list (for os/exec)
- envMap map[string]string // environment mapping (matches env)
- stdout string // standard output from last 'go' command; for 'stdout' command
- stderr string // standard error from last 'go' command; for 'stderr' command
- stopped bool // test wants to stop early
- start time.Time // time phase started
+ t *testing.T
+ workdir string // temporary work dir ($WORK)
+ log bytes.Buffer // test execution log (printed at end of test)
+ mark int // offset of next log truncation
+ cd string // current directory during test execution; initially $WORK/gopath/src
+ name string // short name of test ("foo")
+ file string // full file name ("testdata/script/foo.txt")
+ lineno int // line number currently executing
+ line string // line currently executing
+ env []string // environment list (for os/exec)
+ envMap map[string]string // environment mapping (matches env)
+ stdout string // standard output from last 'go' command; for 'stdout' command
+ stderr string // standard error from last 'go' command; for 'stderr' command
+ stopped bool // test wants to stop early
+ start time.Time // time phase started
+ background []backgroundCmd // backgrounded 'exec' and 'go' commands
+}
+
+type backgroundCmd struct {
+ cmd *exec.Cmd
+ wait <-chan struct{}
+ neg bool // if true, cmd should fail
}
var extraEnvKeys = []string{
@@ -102,6 +112,7 @@ func (ts *testScript) setup() {
"GOROOT=" + testGOROOT,
tempEnvName() + "=" + filepath.Join(ts.workdir, "tmp"),
"devnull=" + os.DevNull,
+ "goversion=" + goVersion(ts),
":=" + string(os.PathListSeparator),
}
@@ -128,6 +139,16 @@ func (ts *testScript) setup() {
}
}
+// goVersion returns the current Go version.
+func goVersion(ts *testScript) string {
+ tags := build.Default.ReleaseTags
+ version := tags[len(tags)-1]
+ if !regexp.MustCompile(`^go([1-9][0-9]*)\.(0|[1-9][0-9]*)$`).MatchString(version) {
+ ts.fatalf("invalid go version %q", version)
+ }
+ return version[2:]
+}
+
var execCache par.Cache
// run runs the test script.
@@ -152,6 +173,17 @@ func (ts *testScript) run() {
}
defer func() {
+ // On a normal exit from the test loop, background processes are cleaned up
+ // before we print PASS. If we return early (e.g., due to a test failure),
+ // don't print anything about the processes that were still running.
+ for _, bg := range ts.background {
+ interruptProcess(bg.cmd.Process)
+ }
+ for _, bg := range ts.background {
+ <-bg.wait
+ }
+ ts.background = nil
+
markTime()
// Flush testScript log to testing.T log.
ts.t.Log("\n" + ts.abbrev(ts.log.String()))
@@ -249,12 +281,19 @@ Script:
ok = testenv.HasExternalNetwork()
case "link":
ok = testenv.HasLink()
+ case "root":
+ ok = os.Geteuid() == 0
case "symlink":
ok = testenv.HasSymlink()
default:
if strings.HasPrefix(cond, "exec:") {
prog := cond[len("exec:"):]
ok = execCache.Do(prog, func() interface{} {
+ if runtime.GOOS == "plan9" && prog == "git" {
+ // The Git command is usually not the real Git on Plan 9.
+ // See https://golang.org/issues/29640.
+ return false
+ }
_, err := exec.LookPath(prog)
return err == nil
}).(bool)
@@ -290,14 +329,23 @@ Script:
// Command can ask script to stop early.
if ts.stopped {
- return
+ // Break instead of returning, so that we check the status of any
+ // background processes and print PASS.
+ break
}
}
+ for _, bg := range ts.background {
+ interruptProcess(bg.cmd.Process)
+ }
+ ts.cmdWait(false, nil)
+
// Final phase ended.
rewind()
markTime()
- fmt.Fprintf(&ts.log, "PASS\n")
+ if !ts.stopped {
+ fmt.Fprintf(&ts.log, "PASS\n")
+ }
}
// scriptCmds are the script command implementations.
@@ -307,8 +355,11 @@ Script:
//
var scriptCmds = map[string]func(*testScript, bool, []string){
"addcrlf": (*testScript).cmdAddcrlf,
+ "cc": (*testScript).cmdCc,
"cd": (*testScript).cmdCd,
+ "chmod": (*testScript).cmdChmod,
"cmp": (*testScript).cmdCmp,
+ "cmpenv": (*testScript).cmdCmpenv,
"cp": (*testScript).cmdCp,
"env": (*testScript).cmdEnv,
"exec": (*testScript).cmdExec,
@@ -323,6 +374,7 @@ var scriptCmds = map[string]func(*testScript, bool, []string){
"stdout": (*testScript).cmdStdout,
"stop": (*testScript).cmdStop,
"symlink": (*testScript).cmdSymlink,
+ "wait": (*testScript).cmdWait,
}
// addcrlf adds CRLF line endings to the named files.
@@ -335,10 +387,21 @@ func (ts *testScript) cmdAddcrlf(neg bool, args []string) {
file = ts.mkabs(file)
data, err := ioutil.ReadFile(file)
ts.check(err)
- ts.check(ioutil.WriteFile(file, bytes.Replace(data, []byte("\n"), []byte("\r\n"), -1), 0666))
+ ts.check(ioutil.WriteFile(file, bytes.ReplaceAll(data, []byte("\n"), []byte("\r\n")), 0666))
}
}
+// cc runs the C compiler along with platform specific options.
+func (ts *testScript) cmdCc(neg bool, args []string) {
+ if len(args) < 1 || (len(args) == 1 && args[0] == "&") {
+ ts.fatalf("usage: cc args... [&]")
+ }
+
+ var b work.Builder
+ b.Init()
+ ts.cmdExec(neg, append(b.GccCmd(".", ""), args...))
+}
+
// cd changes to a different directory.
func (ts *testScript) cmdCd(neg bool, args []string) {
if neg {
@@ -364,6 +427,24 @@ func (ts *testScript) cmdCd(neg bool, args []string) {
fmt.Fprintf(&ts.log, "%s\n", ts.cd)
}
+// chmod changes permissions for a file or directory.
+func (ts *testScript) cmdChmod(neg bool, args []string) {
+ if neg {
+ ts.fatalf("unsupported: ! chmod")
+ }
+ if len(args) < 2 {
+ ts.fatalf("usage: chmod perm paths...")
+ }
+ perm, err := strconv.ParseUint(args[0], 0, 32)
+ if err != nil || perm&uint64(os.ModePerm) != perm {
+ ts.fatalf("invalid mode: %s", args[0])
+ }
+ for _, path := range args[1:] {
+ err := os.Chmod(path, os.FileMode(perm))
+ ts.check(err)
+ }
+}
+
// cmp compares two files.
func (ts *testScript) cmdCmp(neg bool, args []string) {
if neg {
@@ -373,7 +454,21 @@ func (ts *testScript) cmdCmp(neg bool, args []string) {
if len(args) != 2 {
ts.fatalf("usage: cmp file1 file2")
}
+ ts.doCmdCmp(args, false)
+}
+// cmpenv compares two files with environment variable substitution.
+func (ts *testScript) cmdCmpenv(neg bool, args []string) {
+ if neg {
+ ts.fatalf("unsupported: ! cmpenv")
+ }
+ if len(args) != 2 {
+ ts.fatalf("usage: cmpenv file1 file2")
+ }
+ ts.doCmdCmp(args, true)
+}
+
+func (ts *testScript) doCmdCmp(args []string, env bool) {
name1, name2 := args[0], args[1]
var text1, text2 string
if name1 == "stdout" {
@@ -390,6 +485,11 @@ func (ts *testScript) cmdCmp(neg bool, args []string) {
ts.check(err)
text2 = string(data)
+ if env {
+ text1 = ts.expand(text1)
+ text2 = ts.expand(text2)
+ }
+
if text1 == text2 {
return
}
@@ -457,26 +557,43 @@ func (ts *testScript) cmdEnv(neg bool, args []string) {
// exec runs the given command.
func (ts *testScript) cmdExec(neg bool, args []string) {
- if len(args) < 1 {
- ts.fatalf("usage: exec program [args...]")
+ if len(args) < 1 || (len(args) == 1 && args[0] == "&") {
+ ts.fatalf("usage: exec program [args...] [&]")
}
+
var err error
- ts.stdout, ts.stderr, err = ts.exec(args[0], args[1:]...)
- if ts.stdout != "" {
- fmt.Fprintf(&ts.log, "[stdout]\n%s", ts.stdout)
- }
- if ts.stderr != "" {
- fmt.Fprintf(&ts.log, "[stderr]\n%s", ts.stderr)
+ if len(args) > 0 && args[len(args)-1] == "&" {
+ var cmd *exec.Cmd
+ cmd, err = ts.execBackground(args[0], args[1:len(args)-1]...)
+ if err == nil {
+ wait := make(chan struct{})
+ go func() {
+ ctxWait(testCtx, cmd)
+ close(wait)
+ }()
+ ts.background = append(ts.background, backgroundCmd{cmd, wait, neg})
+ }
+ ts.stdout, ts.stderr = "", ""
+ } else {
+ ts.stdout, ts.stderr, err = ts.exec(args[0], args[1:]...)
+ if ts.stdout != "" {
+ fmt.Fprintf(&ts.log, "[stdout]\n%s", ts.stdout)
+ }
+ if ts.stderr != "" {
+ fmt.Fprintf(&ts.log, "[stderr]\n%s", ts.stderr)
+ }
+ if err == nil && neg {
+ ts.fatalf("unexpected command success")
+ }
}
+
if err != nil {
fmt.Fprintf(&ts.log, "[%v]\n", err)
- if !neg {
+ if testCtx.Err() != nil {
+ ts.fatalf("test timed out while running command")
+ } else if !neg {
ts.fatalf("unexpected command failure")
}
- } else {
- if neg {
- ts.fatalf("unexpected command success")
- }
}
}
@@ -551,6 +668,14 @@ func (ts *testScript) cmdSkip(neg bool, args []string) {
if neg {
ts.fatalf("unsupported: ! skip")
}
+
+ // Before we mark the test as skipped, shut down any background processes and
+ // make sure they have returned the correct status.
+ for _, bg := range ts.background {
+ interruptProcess(bg.cmd.Process)
+ }
+ ts.cmdWait(false, nil)
+
if len(args) == 1 {
ts.t.Skip(args[0])
}
@@ -620,7 +745,7 @@ func scriptMatch(ts *testScript, neg bool, args []string, text, name string) {
want = 2
}
if len(args) != want {
- ts.fatalf("usage: %s [-count=N] 'pattern' file%s", name, extraUsage)
+ ts.fatalf("usage: %s [-count=N] 'pattern'%s", name, extraUsage)
}
pattern := args[0]
@@ -636,7 +761,7 @@ func scriptMatch(ts *testScript, neg bool, args []string, text, name string) {
}
// Matching against workdir would be misleading.
- text = strings.Replace(text, ts.workdir, "$WORK", -1)
+ text = strings.ReplaceAll(text, ts.workdir, "$WORK")
if neg {
if re.MatchString(text) {
@@ -693,11 +818,57 @@ func (ts *testScript) cmdSymlink(neg bool, args []string) {
ts.check(os.Symlink(args[2], ts.mkabs(args[0])))
}
+// wait waits for background commands to exit, setting stderr and stdout to their result.
+func (ts *testScript) cmdWait(neg bool, args []string) {
+ if neg {
+ ts.fatalf("unsupported: ! wait")
+ }
+ if len(args) > 0 {
+ ts.fatalf("usage: wait")
+ }
+
+ var stdouts, stderrs []string
+ for _, bg := range ts.background {
+ <-bg.wait
+
+ args := append([]string{filepath.Base(bg.cmd.Args[0])}, bg.cmd.Args[1:]...)
+ fmt.Fprintf(&ts.log, "[background] %s: %v\n", strings.Join(args, " "), bg.cmd.ProcessState)
+
+ cmdStdout := bg.cmd.Stdout.(*strings.Builder).String()
+ if cmdStdout != "" {
+ fmt.Fprintf(&ts.log, "[stdout]\n%s", cmdStdout)
+ stdouts = append(stdouts, cmdStdout)
+ }
+
+ cmdStderr := bg.cmd.Stderr.(*strings.Builder).String()
+ if cmdStderr != "" {
+ fmt.Fprintf(&ts.log, "[stderr]\n%s", cmdStderr)
+ stderrs = append(stderrs, cmdStderr)
+ }
+
+ if bg.cmd.ProcessState.Success() {
+ if bg.neg {
+ ts.fatalf("unexpected command success")
+ }
+ } else {
+ if testCtx.Err() != nil {
+ ts.fatalf("test timed out while running command")
+ } else if !bg.neg {
+ ts.fatalf("unexpected command failure")
+ }
+ }
+ }
+
+ ts.stdout = strings.Join(stdouts, "")
+ ts.stderr = strings.Join(stderrs, "")
+ ts.background = nil
+}
+
// Helpers for command implementations.
// abbrev abbreviates the actual work directory in the string s to the literal string "$WORK".
func (ts *testScript) abbrev(s string) string {
- s = strings.Replace(s, ts.workdir, "$WORK", -1)
+ s = strings.ReplaceAll(s, ts.workdir, "$WORK")
if *testWork {
// Expose actual $WORK value in environment dump on first line of work script,
// so that the user can find out what directory -testwork left behind.
@@ -722,10 +893,51 @@ func (ts *testScript) exec(command string, args ...string) (stdout, stderr strin
var stdoutBuf, stderrBuf strings.Builder
cmd.Stdout = &stdoutBuf
cmd.Stderr = &stderrBuf
- err = cmd.Run()
+ if err = cmd.Start(); err == nil {
+ err = ctxWait(testCtx, cmd)
+ }
return stdoutBuf.String(), stderrBuf.String(), err
}
+// execBackground starts the given command line (an actual subprocess, not simulated)
+// in ts.cd with environment ts.env.
+func (ts *testScript) execBackground(command string, args ...string) (*exec.Cmd, error) {
+ cmd := exec.Command(command, args...)
+ cmd.Dir = ts.cd
+ cmd.Env = append(ts.env, "PWD="+ts.cd)
+ var stdoutBuf, stderrBuf strings.Builder
+ cmd.Stdout = &stdoutBuf
+ cmd.Stderr = &stderrBuf
+ return cmd, cmd.Start()
+}
+
+// ctxWait is like cmd.Wait, but terminates cmd with os.Interrupt if ctx becomes done.
+//
+// This differs from exec.CommandContext in that it prefers os.Interrupt over os.Kill.
+// (See https://golang.org/issue/21135.)
+func ctxWait(ctx context.Context, cmd *exec.Cmd) error {
+ errc := make(chan error, 1)
+ go func() { errc <- cmd.Wait() }()
+
+ select {
+ case err := <-errc:
+ return err
+ case <-ctx.Done():
+ interruptProcess(cmd.Process)
+ return <-errc
+ }
+}
+
+// interruptProcess sends os.Interrupt to p if supported, or os.Kill otherwise.
+func interruptProcess(p *os.Process) {
+ if err := p.Signal(os.Interrupt); err != nil {
+ // Per https://golang.org/pkg/os/#Signal, “Interrupt is not implemented on
+ // Windows; using it with os.Process.Signal will return an error.”
+ // Fall back to Kill instead.
+ p.Kill()
+ }
+}
+
// expand applies environment variable expansion to the string s.
func (ts *testScript) expand(s string) string {
return os.Expand(s, func(key string) string { return ts.envMap[key] })
@@ -891,17 +1103,17 @@ var diffTests = []struct {
func TestDiff(t *testing.T) {
for _, tt := range diffTests {
// Turn spaces into \n.
- text1 := strings.Replace(tt.text1, " ", "\n", -1)
+ text1 := strings.ReplaceAll(tt.text1, " ", "\n")
if text1 != "" {
text1 += "\n"
}
- text2 := strings.Replace(tt.text2, " ", "\n", -1)
+ text2 := strings.ReplaceAll(tt.text2, " ", "\n")
if text2 != "" {
text2 += "\n"
}
out := diff(text1, text2)
// Cut final \n, cut spaces, turn remaining \n into spaces.
- out = strings.Replace(strings.Replace(strings.TrimSuffix(out, "\n"), " ", "", -1), "\n", " ", -1)
+ out = strings.ReplaceAll(strings.ReplaceAll(strings.TrimSuffix(out, "\n"), " ", ""), "\n", " ")
if out != tt.diff {
t.Errorf("diff(%q, %q) = %q, want %q", text1, text2, out, tt.diff)
}
diff --git a/libgo/go/cmd/go/testdata/addmod.go b/libgo/go/cmd/go/testdata/addmod.go
index 19850af0f37..8bb6056a540 100644
--- a/libgo/go/cmd/go/testdata/addmod.go
+++ b/libgo/go/cmd/go/testdata/addmod.go
@@ -142,7 +142,7 @@ func main() {
}
data := txtar.Format(a)
- target := filepath.Join("mod", strings.Replace(path, "/", "_", -1)+"_"+vers+".txt")
+ target := filepath.Join("mod", strings.ReplaceAll(path, "/", "_")+"_"+vers+".txt")
if err := ioutil.WriteFile(target, data, 0666); err != nil {
log.Printf("%s: %v", arg, err)
exitCode = 1
diff --git a/libgo/go/cmd/go/testdata/mod/research.swtch.com_vgo-tour_v1.0.0.txt b/libgo/go/cmd/go/testdata/mod/research.swtch.com_vgo-tour_v1.0.0.txt
deleted file mode 100644
index 0f060dc8e32..00000000000
--- a/libgo/go/cmd/go/testdata/mod/research.swtch.com_vgo-tour_v1.0.0.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-research.swtch.com/vgo-tour@v1.0.0
-
--- .mod --
-module "research.swtch.com/vgo-tour"
--- .info --
-{"Version":"v1.0.0","Name":"84de74b35823c1e49634f2262f1a58cfc951ebae","Short":"84de74b35823","Time":"2018-02-20T00:04:00Z"}
--- go.mod --
-module "research.swtch.com/vgo-tour"
--- hello.go --
-// Copyright 2018 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "fmt"
- "rsc.io/quote"
-)
-
-func main() {
- fmt.Println(quote.Hello())
-}
diff --git a/libgo/go/cmd/go/testdata/script/README b/libgo/go/cmd/go/testdata/script/README
index a80233b8c38..a7b50fff164 100644
--- a/libgo/go/cmd/go/testdata/script/README
+++ b/libgo/go/cmd/go/testdata/script/README
@@ -36,6 +36,7 @@ Scripts also have access to these other environment variables:
PATH=<actual PATH>
TMPDIR=$WORK/tmp
devnull=<value of os.DevNull>
+ goversion=<current Go version; for example, 1.12>
The environment variable $exe (lowercase) is an empty string on most systems, ".exe" on Windows.
@@ -74,6 +75,7 @@ should only run when the condition is satisfied. The available conditions are:
- [cgo], [msan], [race] for whether cgo, msan, and the race detector can be used
- [net] for whether the external network can be used
- [link] for testenv.HasLink()
+ - [root] for os.Geteuid() == 0
- [symlink] for testenv.HasSymlink()
- [exec:prog] for whether prog is available for execution (found by exec.LookPath)
@@ -82,9 +84,17 @@ when testing.Short() is false.
The commands are:
+- [!] cc args... [&]
+ Run the C compiler, the platform specific flags (i.e. `go env GOGCCFLAGS`) will be
+ added automatically before args.
+
- cd dir
Change to the given directory for future commands.
+- chmod perm path...
+ Change the permissions of the files or directories named by the path arguments
+ to be equal to perm. Only numerical permissions are supported.
+
- cmp file1 file2
Check that the named files have the same content.
By convention, file1 is the actual data and file2 the expected data.
@@ -92,6 +102,10 @@ The commands are:
from the most recent exec or go command.
(If the files have differing content, the failure prints a diff.)
+- cmpenv file1 file2
+ Like cmp, but environment variables are substituted in the file contents
+ before the comparison. For example, $GOOS is replaced by the target GOOS.
+
- cp src... dst
Copy the listed files to the target file or existing directory.
@@ -99,16 +113,23 @@ The commands are:
With no arguments, print the environment (useful for debugging).
Otherwise add the listed key=value pairs to the environment.
-- [!] exec program [args...]
+- [!] exec program [args...] [&]
Run the given executable program with the arguments.
It must (or must not) succeed.
Note that 'exec' does not terminate the script (unlike in Unix shells).
+ If the last token is '&', the program executes in the background. The standard
+ output and standard error of the previous command is cleared, but the output
+ of the background process is buffered — and checking of its exit status is
+ delayed — until the next call to 'wait', 'skip', or 'stop' or the end of the
+ test. At the end of the test, any remaining background processes are
+ terminated using os.Interrupt (if supported) or os.Kill.
+
- [!] exists [-readonly] file...
Each of the listed files or directories must (or must not) exist.
If -readonly is given, the files or directories must be unwritable.
-- [!] go args...
+- [!] go args... [&]
Run the (test copy of the) go command with the given arguments.
It must (or must not) succeed.
@@ -131,11 +152,11 @@ The commands are:
- [!] stderr [-count=N] pattern
Apply the grep command (see above) to the standard error
- from the most recent exec or go command.
+ from the most recent exec, go, or wait command.
- [!] stdout [-count=N] pattern
Apply the grep command (see above) to the standard output
- from the most recent exec or go command.
+ from the most recent exec, go, or wait command.
- stop [message]
Stop the test early (marking it as passing), including the message if given.
@@ -143,6 +164,13 @@ The commands are:
- symlink file -> target
Create file as a symlink to target. The -> (like in ls -l output) is required.
+- wait
+ Wait for all 'exec' and 'go' commands started in the background (with the '&'
+ token) to exit, and display success or failure status for them.
+ After a call to wait, the 'stderr' and 'stdout' commands will apply to the
+ concatenation of the corresponding streams of the background commands,
+ in the order in which those commands were started.
+
When TestScript runs a script and the script fails, by default TestScript shows
the execution of the most recent phase of the script (since the last # comment)
and only shows the # comments for earlier phases. For example, here is a
diff --git a/libgo/go/cmd/go/testdata/script/build_GOTMPDIR.txt b/libgo/go/cmd/go/testdata/script/build_GOTMPDIR.txt
index 4c387afbbab..ea06dcc472d 100644
--- a/libgo/go/cmd/go/testdata/script/build_GOTMPDIR.txt
+++ b/libgo/go/cmd/go/testdata/script/build_GOTMPDIR.txt
@@ -1,6 +1,8 @@
+# Set GOCACHE to a clean directory to ensure that 'go build' has work to report.
+env GOCACHE=$WORK/gocache
+
# Build should use GOTMPDIR if set.
env GOTMPDIR=$WORK/my-favorite-tmpdir
-env GOCACHE=off
mkdir $GOTMPDIR
go build -work hello.go
stderr ^WORK=.*my-favorite-tmpdir
@@ -8,4 +10,3 @@ stderr ^WORK=.*my-favorite-tmpdir
-- hello.go --
package main
func main() { println("hello") }
-
diff --git a/libgo/go/cmd/go/testdata/script/help.txt b/libgo/go/cmd/go/testdata/script/help.txt
index cbbd15404b5..9f455256f72 100644
--- a/libgo/go/cmd/go/testdata/script/help.txt
+++ b/libgo/go/cmd/go/testdata/script/help.txt
@@ -28,3 +28,21 @@ stdout 'usage: go mod tidy'
# go mod --help doesn't print help but at least suggests it.
! go mod --help
stderr 'Run ''go help mod'' for usage.'
+
+# Earlier versions of Go printed the same as 'go -h' here.
+# Also make sure we print the short help line.
+! go vet -h
+stderr 'usage: go vet'
+stderr 'Run ''go help vet'' for details'
+stderr 'Run ''go tool vet -help'' for the vet tool''s flags'
+
+# Earlier versions of Go printed a large document here, instead of these two
+# lines.
+! go test -h
+stderr 'usage: go test'
+stderr 'Run ''go help test'' for details'
+
+# go help get shows usage for get
+go help get
+stdout 'usage: go get'
+stdout 'get when using GOPATH'
diff --git a/libgo/go/cmd/go/testdata/script/list_bad_import.txt b/libgo/go/cmd/go/testdata/script/list_bad_import.txt
index ba66b0937f8..3d9cac0d5f5 100644
--- a/libgo/go/cmd/go/testdata/script/list_bad_import.txt
+++ b/libgo/go/cmd/go/testdata/script/list_bad_import.txt
@@ -47,7 +47,7 @@ stdout error
stdout incomplete
-# The pattern "all" should match only packages that acutally exist,
+# The pattern "all" should match only packages that actually exist,
# ignoring those whose existence is merely implied by imports.
go list -e -f '{{.ImportPath}}' all
stdout example.com/direct
diff --git a/libgo/go/cmd/go/testdata/script/list_std.txt b/libgo/go/cmd/go/testdata/script/list_std.txt
index a63d74db120..046bec6ac54 100644
--- a/libgo/go/cmd/go/testdata/script/list_std.txt
+++ b/libgo/go/cmd/go/testdata/script/list_std.txt
@@ -8,5 +8,5 @@ go list -f '{{if not .Standard}}{{.ImportPath}}{{end}}' ./...
# our vendored packages should be reported as standard
go list std cmd
-stdout golang_org/x/net/http2/hpack
+stdout internal/x/net/http2/hpack
stdout cmd/vendor/golang\.org/x/arch/x86/x86asm
diff --git a/libgo/go/cmd/go/testdata/script/mod_download.txt b/libgo/go/cmd/go/testdata/script/mod_download.txt
index 6be6acb360c..22f07c33c75 100644
--- a/libgo/go/cmd/go/testdata/script/mod_download.txt
+++ b/libgo/go/cmd/go/testdata/script/mod_download.txt
@@ -8,6 +8,12 @@ exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.info
exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.mod
exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.zip
+# download of an invalid path should report the error
+! go mod download this.domain.is.invalid/somemodule@v1.0.0
+stderr 'this.domain.is.invalid'
+! go mod download -json this.domain.is.invalid/somemodule@v1.0.0
+stdout '"Error": ".*this.domain.is.invalid.*"'
+
# download -json with version should print JSON
go mod download -json 'rsc.io/quote@<=v1.5.0'
stdout '^\t"Path": "rsc.io/quote"'
@@ -42,6 +48,21 @@ exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod
exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip
exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
+# download repopulates deleted files and directories independently.
+rm $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.info
+go mod download
+exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.info
+rm $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod
+go mod download
+exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod
+rm $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip
+go mod download
+exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip
+rm -r $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
+go mod download
+exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
+
+# download reports the locations of downloaded files
go mod download -json
stdout '^\t"Path": "rsc.io/quote"'
stdout '^\t"Version": "v1.5.2"'
diff --git a/libgo/go/cmd/go/testdata/script/mod_edit.txt b/libgo/go/cmd/go/testdata/script/mod_edit.txt
index 60a6f745361..aa714e8b3cd 100644
--- a/libgo/go/cmd/go/testdata/script/mod_edit.txt
+++ b/libgo/go/cmd/go/testdata/script/mod_edit.txt
@@ -10,37 +10,43 @@ stderr 'cannot determine module path'
go mod init x.x/y/z
stderr 'creating new go.mod: module x.x/y/z'
-cmp go.mod $WORK/go.mod.init
+cmpenv go.mod $WORK/go.mod.init
! go mod init
-cmp go.mod $WORK/go.mod.init
+cmpenv go.mod $WORK/go.mod.init
# go mod edits
go mod edit -droprequire=x.1 -require=x.1@v1.0.0 -require=x.2@v1.1.0 -droprequire=x.2 -exclude='x.1 @ v1.2.0' -exclude=x.1@v1.2.1 -replace=x.1@v1.3.0=y.1@v1.4.0 -replace='x.1@v1.4.0 = ../z'
-cmp go.mod $WORK/go.mod.edit1
+cmpenv go.mod $WORK/go.mod.edit1
go mod edit -droprequire=x.1 -dropexclude=x.1@v1.2.1 -dropreplace=x.1@v1.3.0 -require=x.3@v1.99.0
-cmp go.mod $WORK/go.mod.edit2
+cmpenv go.mod $WORK/go.mod.edit2
# go mod edit -json
go mod edit -json
-cmp stdout $WORK/go.mod.json
+cmpenv stdout $WORK/go.mod.json
# go mod edit -replace
go mod edit -replace=x.1@v1.3.0=y.1/v2@v2.3.5 -replace=x.1@v1.4.0=y.1/v2@v2.3.5
-cmp go.mod $WORK/go.mod.edit3
+cmpenv go.mod $WORK/go.mod.edit3
go mod edit -replace=x.1=y.1/v2@v2.3.6
-cmp go.mod $WORK/go.mod.edit4
+cmpenv go.mod $WORK/go.mod.edit4
go mod edit -dropreplace=x.1
-cmp go.mod $WORK/go.mod.edit5
+cmpenv go.mod $WORK/go.mod.edit5
# go mod edit -fmt
cp $WORK/go.mod.badfmt go.mod
go mod edit -fmt -print # -print should avoid writing file
-cmp stdout $WORK/go.mod.edit4
+cmpenv stdout $WORK/go.mod.edit6
cmp go.mod $WORK/go.mod.badfmt
go mod edit -fmt # without -print, should write file (and nothing to stdout)
! stdout .
-cmp go.mod $WORK/go.mod.edit4
+cmpenv go.mod $WORK/go.mod.edit6
+
+# go mod edit -module
+cd $WORK/m
+go mod init a.a/b/c
+go mod edit -module x.x/y/z
+cmpenv go.mod go.mod.edit
-- x.go --
package x
@@ -50,9 +56,13 @@ package w
-- $WORK/go.mod.init --
module x.x/y/z
+
+go $goversion
-- $WORK/go.mod.edit1 --
module x.x/y/z
+go $goversion
+
require x.1 v1.0.0
exclude (
@@ -67,6 +77,8 @@ replace (
-- $WORK/go.mod.edit2 --
module x.x/y/z
+go $goversion
+
exclude x.1 v1.2.0
replace x.1 v1.4.0 => ../z
@@ -77,6 +89,7 @@ require x.3 v1.99.0
"Module": {
"Path": "x.x/y/z"
},
+ "Go": "$goversion",
"Require": [
{
"Path": "x.3",
@@ -104,6 +117,8 @@ require x.3 v1.99.0
-- $WORK/go.mod.edit3 --
module x.x/y/z
+go $goversion
+
exclude x.1 v1.2.0
replace (
@@ -115,6 +130,8 @@ require x.3 v1.99.0
-- $WORK/go.mod.edit4 --
module x.x/y/z
+go $goversion
+
exclude x.1 v1.2.0
replace x.1 => y.1/v2 v2.3.6
@@ -123,14 +140,32 @@ require x.3 v1.99.0
-- $WORK/go.mod.edit5 --
module x.x/y/z
+go $goversion
+
+exclude x.1 v1.2.0
+
+require x.3 v1.99.0
+-- $WORK/go.mod.edit6 --
+module x.x/y/z
+
+go 1.10
+
exclude x.1 v1.2.0
+replace x.1 => y.1/v2 v2.3.6
+
require x.3 v1.99.0
-- $WORK/go.mod.badfmt --
module x.x/y/z
+go 1.10
+
exclude x.1 v1.2.0
replace x.1 => y.1/v2 v2.3.6
require x.3 v1.99.0
+-- $WORK/m/go.mod.edit --
+module x.x/y/z
+
+go $goversion \ No newline at end of file
diff --git a/libgo/go/cmd/go/testdata/script/mod_enabled.txt b/libgo/go/cmd/go/testdata/script/mod_enabled.txt
index 8eef870b02b..ab5ee3d6dfa 100644
--- a/libgo/go/cmd/go/testdata/script/mod_enabled.txt
+++ b/libgo/go/cmd/go/testdata/script/mod_enabled.txt
@@ -38,9 +38,9 @@ stdout z[/\\]go.mod
cd $GOPATH/src/x/y
go env GOMOD
-! stdout .
-! go list -m
-stderr 'cannot find main module'
+stdout 'NUL|/dev/null'
+go list -m
+stdout '^command-line-arguments$'
cd $GOPATH/foo
go env GOMOD
diff --git a/libgo/go/cmd/go/testdata/script/mod_fs_patterns.txt b/libgo/go/cmd/go/testdata/script/mod_fs_patterns.txt
index d7d3e0321b5..9341a1d0830 100644
--- a/libgo/go/cmd/go/testdata/script/mod_fs_patterns.txt
+++ b/libgo/go/cmd/go/testdata/script/mod_fs_patterns.txt
@@ -34,11 +34,11 @@ stderr 'import lookup disabled'
! go build -mod=readonly ./nonexist
! stderr 'import lookup disabled'
-stderr '^go: no such directory ./nonexist'
+stderr 'unknown import path "m/nonexist": cannot find package'
! go build -mod=readonly ./go.mod
! stderr 'import lookup disabled'
-stderr '^go: ./go.mod is not a directory'
+stderr 'unknown import path "m/go.mod": cannot find package'
-- x/go.mod --
module m
diff --git a/libgo/go/cmd/go/testdata/script/mod_go_version.txt b/libgo/go/cmd/go/testdata/script/mod_go_version.txt
index f2de74cee87..37f173531b6 100644
--- a/libgo/go/cmd/go/testdata/script/mod_go_version.txt
+++ b/libgo/go/cmd/go/testdata/script/mod_go_version.txt
@@ -3,9 +3,10 @@
env GO111MODULE=on
go list
-! go build
-stderr 'module requires Go 1.999'
+go build
go build sub.1
+go build subver.1
+! stderr 'module requires'
! go build badsub.1
stderr 'module requires Go 1.11111'
@@ -19,11 +20,13 @@ module m
go 1.999
require (
sub.1 v1.0.0
+ subver.1 v1.0.0
badsub.1 v1.0.0
versioned.1 v1.0.0
)
replace (
sub.1 => ./sub
+ subver.1 => ./subver
badsub.1 => ./badsub
versioned.1 v1.0.0 => ./versioned1
versioned.1 v1.1.0 => ./versioned2
@@ -39,12 +42,20 @@ go 1.11
-- sub/x.go --
package x
+-- subver/go.mod --
+module m
+go 1.11111
+
+-- subver/x.go --
+package x
+
-- badsub/go.mod --
module m
go 1.11111
-- badsub/x.go --
package x
+invalid syntax
-- versioned1/go.mod --
module versioned
@@ -59,3 +70,4 @@ go 1.99999
-- versioned2/x.go --
package x
+invalid syntax
diff --git a/libgo/go/cmd/go/testdata/script/mod_internal.txt b/libgo/go/cmd/go/testdata/script/mod_internal.txt
index 72706fdc7b4..5a47c3fa44a 100644
--- a/libgo/go/cmd/go/testdata/script/mod_internal.txt
+++ b/libgo/go/cmd/go/testdata/script/mod_internal.txt
@@ -18,15 +18,6 @@ stderr 'use of internal package golang.org/x/.* not allowed'
! go build ./fromstd
stderr 'use of internal package internal/testenv not allowed'
-# Packages found via standard-library vendoring should not leak.
-! go build ./fromstdvendor
-stderr 'use of vendored package golang_org/x/net/http/httpguts not allowed'
-
-env GO111MODULE=off
-! go build ./fromstdvendor
-[!gccgo] stderr 'cannot find package "golang_org/x/net/http/httpguts" in any of:'
-env GO111MODULE=on
-
# Dependencies should be able to use their own internal modules...
rm go.mod
go mod init golang.org/notx
@@ -83,10 +74,6 @@ import _ "golang.org/notx/useinternal"
package fromstd
import _ "internal/testenv"
--- fromstdvendor/useinternal.go --
-package fromstdvendor
-import _ "golang_org/x/net/http/httpguts"
-
-- replace/golang.org/notx/internal/go.mod --
module golang.org/x/internal
diff --git a/libgo/go/cmd/go/testdata/script/mod_list_bad_import.txt b/libgo/go/cmd/go/testdata/script/mod_list_bad_import.txt
index 258eb6a5671..8a66e0b72a0 100644
--- a/libgo/go/cmd/go/testdata/script/mod_list_bad_import.txt
+++ b/libgo/go/cmd/go/testdata/script/mod_list_bad_import.txt
@@ -47,7 +47,7 @@ stdout error
stdout incomplete
-# The pattern "all" should match only packages that acutally exist,
+# The pattern "all" should match only packages that actually exist,
# ignoring those whose existence is merely implied by imports.
go list -e -f '{{.ImportPath}} {{.Error}}' all
stdout example.com/direct
diff --git a/libgo/go/cmd/go/testdata/script/mod_list_dir.txt b/libgo/go/cmd/go/testdata/script/mod_list_dir.txt
index 6d9414794e5..31cd27d7561 100644
--- a/libgo/go/cmd/go/testdata/script/mod_list_dir.txt
+++ b/libgo/go/cmd/go/testdata/script/mod_list_dir.txt
@@ -12,7 +12,9 @@ stdout ^math$
go list -f '{{.ImportPath}}' .
stdout ^x$
! go list -f '{{.ImportPath}}' $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
-stderr '^go: no such directory.*quote@v1.5.2'
+stderr 'unknown import path "rsc.io/quote": cannot find package'
+go list -e -f '{{with .Error}}{{.}}{{end}}' $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
+stdout 'unknown import path "rsc.io/quote": cannot find package'
go mod download rsc.io/quote@v1.5.2
go list -f '{{.ImportPath}}' $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
stdout '^rsc.io/quote$'
diff --git a/libgo/go/cmd/go/testdata/script/mod_nomod.txt b/libgo/go/cmd/go/testdata/script/mod_nomod.txt
index c6fb791c514..b347deea7ff 100644
--- a/libgo/go/cmd/go/testdata/script/mod_nomod.txt
+++ b/libgo/go/cmd/go/testdata/script/mod_nomod.txt
@@ -16,7 +16,7 @@ go mod edit -json x.mod
! go get
! go install
! go list
-! go run x.go
+! go run
! go test
! go vet
diff --git a/libgo/go/cmd/go/testdata/script/mod_patterns.txt b/libgo/go/cmd/go/testdata/script/mod_patterns.txt
index 9b2ebdf02b9..539b64a2461 100644
--- a/libgo/go/cmd/go/testdata/script/mod_patterns.txt
+++ b/libgo/go/cmd/go/testdata/script/mod_patterns.txt
@@ -34,6 +34,13 @@ env CGO_ENABLED=0
go list -f '{{.ImportPath}}: {{.Match}}' all ... example.com/m/... ./... ./xyz...
! stdout example.com/m/useC
+# 'go list ./...' should not try to resolve the main module.
+cd ../empty
+go list -deps ./...
+! stdout .
+! stderr 'finding'
+stderr -count=1 '^go: warning: "./..." matched no packages'
+
-- m/go.mod --
module example.com/m
@@ -64,3 +71,6 @@ module example.com/m/nested
-- nested/useencoding/useencoding.go --
package useencoding
import _ "encoding"
+
+-- empty/go.mod --
+module example.com/empty
diff --git a/libgo/go/cmd/go/testdata/script/mod_readonly.txt b/libgo/go/cmd/go/testdata/script/mod_readonly.txt
index 1b5932e441e..188a66d0e15 100644
--- a/libgo/go/cmd/go/testdata/script/mod_readonly.txt
+++ b/libgo/go/cmd/go/testdata/script/mod_readonly.txt
@@ -37,6 +37,8 @@ cmp go.mod go.mod.inconsistent
-- go.mod --
module m
+go 1.20
+
-- x.go --
package x
import _ "rsc.io/quote"
diff --git a/libgo/go/cmd/go/testdata/script/mod_replace.txt b/libgo/go/cmd/go/testdata/script/mod_replace.txt
index 5894ed69f34..78d6729fce3 100644
--- a/libgo/go/cmd/go/testdata/script/mod_replace.txt
+++ b/libgo/go/cmd/go/testdata/script/mod_replace.txt
@@ -1,10 +1,14 @@
env GO111MODULE=on
+cp go.mod go.mod.orig
+
+# Make sure the test builds without replacement.
go build -o a1.exe .
exec ./a1.exe
stdout 'Don''t communicate by sharing memory'
# Modules can be replaced by local packages.
+cp go.mod.orig go.mod
go mod edit -replace=rsc.io/quote/v3=./local/rsc.io/quote/v3
go build -o a2.exe .
exec ./a2.exe
@@ -12,16 +16,27 @@ stdout 'Concurrency is not parallelism.'
# The module path of the replacement doesn't need to match.
# (For example, it could be a long-running fork with its own import path.)
+cp go.mod.orig go.mod
go mod edit -replace=rsc.io/quote/v3=./local/not-rsc.io/quote/v3
go build -o a3.exe .
exec ./a3.exe
stdout 'Clear is better than clever.'
# However, the same module can't be used as two different paths.
-go mod edit -dropreplace=rsc.io/quote/v3 -replace=not-rsc.io/quote/v3@v3.0.0=rsc.io/quote/v3@v3.0.0 -require=not-rsc.io/quote/v3@v3.0.0
+cp go.mod.orig go.mod
+go mod edit -replace=not-rsc.io/quote/v3@v3.0.0=rsc.io/quote/v3@v3.0.0 -require=not-rsc.io/quote/v3@v3.0.0
! go build -o a4.exe .
stderr 'rsc.io/quote/v3@v3.0.0 used for two different module paths \(not-rsc.io/quote/v3 and rsc.io/quote/v3\)'
+# Modules that do not (yet) exist upstream can be replaced too.
+cp go.mod.orig go.mod
+go mod edit -replace=not-rsc.io/quote/v3@v3.1.0=./local/rsc.io/quote/v3
+go build -o a5.exe ./usenewmodule
+! stderr 'finding not-rsc.io/quote/v3'
+grep 'not-rsc.io/quote/v3 v3.1.0' go.mod
+exec ./a5.exe
+stdout 'Concurrency is not parallelism.'
+
-- go.mod --
module quoter
@@ -39,6 +54,18 @@ func main() {
fmt.Println(quote.GoV3())
}
+-- usenewmodule/main.go --
+package main
+
+import (
+ "fmt"
+ "not-rsc.io/quote/v3"
+)
+
+func main() {
+ fmt.Println(quote.GoV3())
+}
+
-- local/rsc.io/quote/v3/go.mod --
module rsc.io/quote/v3
diff --git a/libgo/go/cmd/go/testdata/script/mod_test.txt b/libgo/go/cmd/go/testdata/script/mod_test.txt
index caeb25ada84..af4fd76d706 100644
--- a/libgo/go/cmd/go/testdata/script/mod_test.txt
+++ b/libgo/go/cmd/go/testdata/script/mod_test.txt
@@ -1,5 +1,8 @@
env GO111MODULE=on
+# TODO(bcmills): Convert the 'go test' calls below to 'go list -test' once 'go
+# list' is more sensitive to package loading errors.
+
# A test in the module's root package should work.
cd a/
cp go.mod.empty go.mod
@@ -48,6 +51,10 @@ cd ../d_test
go test
stdout PASS
+cd ../e
+go test
+stdout PASS
+
-- a/go.mod.empty --
module example.com/user/a
diff --git a/libgo/go/cmd/go/testdata/script/mod_tidy.txt b/libgo/go/cmd/go/testdata/script/mod_tidy.txt
index 449aa073a78..de3b52e2c02 100644
--- a/libgo/go/cmd/go/testdata/script/mod_tidy.txt
+++ b/libgo/go/cmd/go/testdata/script/mod_tidy.txt
@@ -5,6 +5,9 @@ go mod tidy -v
stderr '^unused y.1'
! stderr '^unused [^y]'
+# tidy should not touch existing go line
+grep 'go 1.10' go.mod
+
go list -m all
! stdout '^y'
stdout '^w.1 v1.2.0'
@@ -12,11 +15,17 @@ stdout '^z.1 v1.2.0'
# empty tidy should not crash
cd triv
+! grep 'go ' go.mod
go mod tidy
+# tidy should add missing go line
+grep 'go ' go.mod
+
-- go.mod --
module m
+go 1.10
+
require (
x.1 v1.0.0
y.1 v1.0.0
diff --git a/libgo/go/cmd/go/testdata/script/mod_vendor.txt b/libgo/go/cmd/go/testdata/script/mod_vendor.txt
index b3769a85041..203183be881 100644
--- a/libgo/go/cmd/go/testdata/script/mod_vendor.txt
+++ b/libgo/go/cmd/go/testdata/script/mod_vendor.txt
@@ -67,6 +67,7 @@ module m
require (
a v1.0.0
+ diamondroot v0.0.0
mysite/myname/mypkg v1.0.0
w v1.0.0 // indirect
x v1.0.0
@@ -76,6 +77,10 @@ require (
replace (
a v1.0.0 => ./a
+ diamondleft => ./diamondleft
+ diamondpoint => ./diamondpoint
+ diamondright => ./diamondright
+ diamondroot => ./diamondroot
mysite/myname/mypkg v1.0.0 => ./mypkg
w v1.0.0 => ./w
x v1.0.0 => ./x
@@ -200,6 +205,10 @@ import _ "z"
package m
import _ "x/x1"
+-- importdiamond.go --
+package m
+
+import _ "diamondroot"
-- w/go.mod --
module w
-- w/w.go --
@@ -228,3 +237,42 @@ package y
module z
-- z/z.go --
package z
+
+-- diamondroot/go.mod --
+module diamondroot
+
+require (
+ diamondleft v0.0.0
+ diamondright v0.0.0
+)
+-- diamondroot/x.go --
+package diamondroot
+
+import (
+ _ "diamondleft"
+ _ "diamondright"
+)
+-- diamondleft/go.mod --
+module diamondleft
+
+require (
+ diamondpoint v0.0.0
+)
+-- diamondleft/x.go --
+package diamondleft
+
+import _ "diamondpoint"
+-- diamondright/go.mod --
+module diamondright
+
+require (
+ diamondpoint v0.0.0
+)
+-- diamondright/x.go --
+package diamondright
+
+import _ "diamondpoint"
+-- diamondpoint/go.mod --
+module diamondpoint
+-- diamondpoint/x.go --
+package diamondpoint
diff --git a/libgo/go/cmd/go/testdata/testterminal18153/terminal_test.go b/libgo/go/cmd/go/testdata/testterminal18153/terminal_test.go
index d662e55ee55..71493efe983 100644
--- a/libgo/go/cmd/go/testdata/testterminal18153/terminal_test.go
+++ b/libgo/go/cmd/go/testdata/testterminal18153/terminal_test.go
@@ -5,7 +5,7 @@
// +build linux
// This test is run by src/cmd/dist/test.go (cmd_go_test_terminal),
-// and not by cmd/go's tests. This is because this test requires that
+// and not by cmd/go's tests. This is because this test requires
// that it be called with its stdout and stderr being a terminal.
// dist doesn't run `cmd/go test` against this test directory if
// dist's stdout/stderr aren't terminals.
diff --git a/libgo/go/cmd/go/vendor_test.go b/libgo/go/cmd/go/vendor_test.go
index 22aa643b003..c302d7e9b58 100644
--- a/libgo/go/cmd/go/vendor_test.go
+++ b/libgo/go/cmd/go/vendor_test.go
@@ -37,7 +37,7 @@ func TestVendorImports(t *testing.T) {
vend/x/vendor/p/p [notfound]
vend/x/vendor/r []
`
- want = strings.Replace(want+"\t", "\n\t\t", "\n", -1)
+ want = strings.ReplaceAll(want+"\t", "\n\t\t", "\n")
want = strings.TrimPrefix(want, "\n")
have := tg.stdout.String()
diff --git a/libgo/go/cmd/gofmt/gofmt.go b/libgo/go/cmd/gofmt/gofmt.go
index d5b7be327a5..ac6852f2e4e 100644
--- a/libgo/go/cmd/gofmt/gofmt.go
+++ b/libgo/go/cmd/gofmt/gofmt.go
@@ -319,10 +319,7 @@ func backupFile(filename string, data []byte, perm os.FileMode) (string, error)
}
// write data to backup file
- n, err := f.Write(data)
- if err == nil && n < len(data) {
- err = io.ErrShortWrite
- }
+ _, err = f.Write(data)
if err1 := f.Close(); err == nil {
err = err1
}
diff --git a/libgo/go/cmd/gofmt/gofmt_test.go b/libgo/go/cmd/gofmt/gofmt_test.go
index 16b653b6460..3008365cd23 100644
--- a/libgo/go/cmd/gofmt/gofmt_test.go
+++ b/libgo/go/cmd/gofmt/gofmt_test.go
@@ -200,7 +200,7 @@ func TestDiff(t *testing.T) {
}
if runtime.GOOS == "windows" {
- b = bytes.Replace(b, []byte{'\r', '\n'}, []byte{'\n'}, -1)
+ b = bytes.ReplaceAll(b, []byte{'\r', '\n'}, []byte{'\n'})
}
bs := bytes.SplitN(b, []byte{'\n'}, 3)
diff --git a/libgo/go/cmd/gofmt/long_test.go b/libgo/go/cmd/gofmt/long_test.go
index 237b86021bf..e2a6208f871 100644
--- a/libgo/go/cmd/gofmt/long_test.go
+++ b/libgo/go/cmd/gofmt/long_test.go
@@ -85,6 +85,12 @@ func testFile(t *testing.T, b1, b2 *bytes.Buffer, filename string) {
// the first and 2nd result should be identical
if !bytes.Equal(b1.Bytes(), b2.Bytes()) {
+ // A known instance of gofmt not being idempotent
+ // (see Issue #24472)
+ if strings.HasSuffix(filename, "issue22662.go") {
+ t.Log("known gofmt idempotency bug (Issue #24472)")
+ return
+ }
t.Errorf("gofmt %s not idempotent", filename)
}
}
diff --git a/libgo/go/cmd/internal/buildid/buildid.go b/libgo/go/cmd/internal/buildid/buildid.go
index 41e6c773e1b..ac238d70ea0 100644
--- a/libgo/go/cmd/internal/buildid/buildid.go
+++ b/libgo/go/cmd/internal/buildid/buildid.go
@@ -7,8 +7,8 @@ package buildid
import (
"bytes"
"debug/elf"
- "debug/xcoff"
"fmt"
+ "internal/xcoff"
"io"
"os"
"strconv"
diff --git a/libgo/go/cmd/internal/objabi/doc.go b/libgo/go/cmd/internal/objabi/doc.go
index 7bd5ff63e56..03dc9fb88bc 100644
--- a/libgo/go/cmd/internal/objabi/doc.go
+++ b/libgo/go/cmd/internal/objabi/doc.go
@@ -22,7 +22,7 @@
//
// The file format is:
//
-// - magic header: "\x00\x00go19ld"
+// - magic header: "\x00go112ld"
// - byte 1 - version number
// - sequence of strings giving dependencies (imported packages)
// - empty string (marks end of sequence)
@@ -38,7 +38,7 @@
// - data, the content of the defined symbols
// - sequence of defined symbols
// - byte 0xff (marks end of sequence)
-// - magic footer: "\xff\xffgo19ld"
+// - magic footer: "\xffgo112ld"
//
// All integers are stored in a zigzag varint format.
// See golang.org/s/go12symtab for a definition.
@@ -46,7 +46,7 @@
// Data blocks and strings are both stored as an integer
// followed by that many bytes.
//
-// A symbol reference is a string name followed by a version.
+// A symbol reference is a string name followed by an ABI or -1 for static.
//
// A symbol points to other symbols using an index into the symbol
// reference sequence. Index 0 corresponds to a nil symbol pointer.
@@ -57,7 +57,7 @@
//
// - byte 0xfe (sanity check for synchronization)
// - type [byte]
-// - name & version [symref index]
+// - name & ABI [symref index]
// - flags [int]
// 1<<0 dupok
// 1<<1 local
diff --git a/libgo/go/cmd/internal/objabi/flag.go b/libgo/go/cmd/internal/objabi/flag.go
index 30cd7dccac2..90e944656bb 100644
--- a/libgo/go/cmd/internal/objabi/flag.go
+++ b/libgo/go/cmd/internal/objabi/flag.go
@@ -100,9 +100,18 @@ func (versionFlag) Set(s string) error {
// for releases, but during development we include the full
// build ID of the binary, so that if the compiler is changed and
// rebuilt, we notice and rebuild all packages.
- if s == "full" && strings.HasPrefix(Version, "devel") {
- p += " buildID=" + buildID
+ if s == "full" {
+ // If there's an active experiment, include that,
+ // to distinguish go1.10.2 with an experiment
+ // from go1.10.2 without an experiment.
+ if x := Expstring(); x != "" {
+ p += " " + x
+ }
+ if strings.HasPrefix(Version, "devel") {
+ p += " buildID=" + buildID
+ }
}
+
fmt.Printf("%s version %s%s%s\n", name, Version, sep, p)
os.Exit(0)
return nil
diff --git a/libgo/go/cmd/internal/objabi/funcdata.go b/libgo/go/cmd/internal/objabi/funcdata.go
index a7827125bf6..231d11b1857 100644
--- a/libgo/go/cmd/internal/objabi/funcdata.go
+++ b/libgo/go/cmd/internal/objabi/funcdata.go
@@ -18,6 +18,7 @@ const (
FUNCDATA_LocalsPointerMaps = 1
FUNCDATA_InlTree = 2
FUNCDATA_RegPointerMaps = 3
+ FUNCDATA_StackObjects = 4
// ArgsSizeUnknown is set in Func.argsize to mark all functions
// whose argument size is unknown (C vararg functions, and
diff --git a/libgo/go/cmd/internal/objabi/funcid.go b/libgo/go/cmd/internal/objabi/funcid.go
index 15a63ab8b34..1792df7cc1d 100644
--- a/libgo/go/cmd/internal/objabi/funcid.go
+++ b/libgo/go/cmd/internal/objabi/funcid.go
@@ -4,12 +4,17 @@
package objabi
+import (
+ "strconv"
+ "strings"
+)
+
// A FuncID identifies particular functions that need to be treated
// specially by the runtime.
// Note that in some situations involving plugins, there may be multiple
// copies of a particular special runtime function.
// Note: this list must match the list in runtime/symtab.go.
-type FuncID uint32
+type FuncID uint8
const (
FuncID_normal FuncID = iota // not a special function
@@ -30,4 +35,65 @@ const (
FuncID_gogo
FuncID_externalthreadhandler
FuncID_debugCallV1
+ FuncID_gopanic
+ FuncID_panicwrap
+ FuncID_wrapper // any autogenerated code (hash/eq algorithms, method wrappers, etc.)
)
+
+// Get the function ID for the named function in the named file.
+// The function should be package-qualified.
+func GetFuncID(name, file string) FuncID {
+ switch name {
+ case "runtime.main":
+ return FuncID_runtime_main
+ case "runtime.goexit":
+ return FuncID_goexit
+ case "runtime.jmpdefer":
+ return FuncID_jmpdefer
+ case "runtime.mcall":
+ return FuncID_mcall
+ case "runtime.morestack":
+ return FuncID_morestack
+ case "runtime.mstart":
+ return FuncID_mstart
+ case "runtime.rt0_go":
+ return FuncID_rt0_go
+ case "runtime.asmcgocall":
+ return FuncID_asmcgocall
+ case "runtime.sigpanic":
+ return FuncID_sigpanic
+ case "runtime.runfinq":
+ return FuncID_runfinq
+ case "runtime.gcBgMarkWorker":
+ return FuncID_gcBgMarkWorker
+ case "runtime.systemstack_switch":
+ return FuncID_systemstack_switch
+ case "runtime.systemstack":
+ return FuncID_systemstack
+ case "runtime.cgocallback_gofunc":
+ return FuncID_cgocallback_gofunc
+ case "runtime.gogo":
+ return FuncID_gogo
+ case "runtime.externalthreadhandler":
+ return FuncID_externalthreadhandler
+ case "runtime.debugCallV1":
+ return FuncID_debugCallV1
+ case "runtime.gopanic":
+ return FuncID_gopanic
+ case "runtime.panicwrap":
+ return FuncID_panicwrap
+ }
+ if file == "<autogenerated>" && !strings.HasSuffix(name, ".init") {
+ return FuncID_wrapper
+ }
+ if strings.HasPrefix(name, "runtime.call") {
+ if _, err := strconv.Atoi(name[12:]); err == nil {
+ // runtime.callXX reflect call wrappers.
+ return FuncID_wrapper
+ }
+ }
+ if strings.HasSuffix(name, "-fm") {
+ return FuncID_wrapper
+ }
+ return FuncID_normal
+}
diff --git a/libgo/go/cmd/internal/objabi/head.go b/libgo/go/cmd/internal/objabi/head.go
index 23c7b62daf6..db2221d6b14 100644
--- a/libgo/go/cmd/internal/objabi/head.go
+++ b/libgo/go/cmd/internal/objabi/head.go
@@ -48,10 +48,13 @@ const (
Hplan9
Hsolaris
Hwindows
+ Haix
)
func (h *HeadType) Set(s string) error {
switch s {
+ case "aix":
+ *h = Haix
case "darwin":
*h = Hdarwin
case "dragonfly":
@@ -82,6 +85,8 @@ func (h *HeadType) Set(s string) error {
func (h *HeadType) String() string {
switch *h {
+ case Haix:
+ return "aix"
case Hdarwin:
return "darwin"
case Hdragonfly:
diff --git a/libgo/go/cmd/internal/objabi/reloctype.go b/libgo/go/cmd/internal/objabi/reloctype.go
index a3e2868a1bc..355882c6388 100644
--- a/libgo/go/cmd/internal/objabi/reloctype.go
+++ b/libgo/go/cmd/internal/objabi/reloctype.go
@@ -198,7 +198,7 @@ const (
R_WASMIMPORT
)
-// IsDirectJump returns whether r is a relocation for a direct jump.
+// IsDirectJump reports whether r is a relocation for a direct jump.
// A direct jump is a CALL or JMP instruction that takes the target address
// as immediate. The address is embedded into the instruction, possibly
// with limited width.
diff --git a/libgo/go/cmd/internal/objabi/stack.go b/libgo/go/cmd/internal/objabi/stack.go
index 11433932e2d..62ab0398a66 100644
--- a/libgo/go/cmd/internal/objabi/stack.go
+++ b/libgo/go/cmd/internal/objabi/stack.go
@@ -10,11 +10,24 @@ const (
STACKSYSTEM = 0
StackSystem = STACKSYSTEM
StackBig = 4096
- StackGuard = 880*stackGuardMultiplier + StackSystem
StackSmall = 128
- StackLimit = StackGuard - StackSystem - StackSmall
)
const (
StackPreempt = -1314 // 0xfff...fade
)
+
+// Initialize StackGuard and StackLimit according to target system.
+var StackGuard = 880*stackGuardMultiplier() + StackSystem
+var StackLimit = StackGuard - StackSystem - StackSmall
+
+// stackGuardMultiplier returns a multiplier to apply to the default
+// stack guard size. Larger multipliers are used for non-optimized
+// builds that have larger stack frames or for specific targets.
+func stackGuardMultiplier() int {
+ // On AIX, a larger stack is needed for syscalls.
+ if GOOS == "aix" {
+ return 2
+ }
+ return stackGuardMultiplierDefault
+}
diff --git a/libgo/go/cmd/internal/objabi/symkind.go b/libgo/go/cmd/internal/objabi/symkind.go
index b95a0d3c701..16b4c535ed8 100644
--- a/libgo/go/cmd/internal/objabi/symkind.go
+++ b/libgo/go/cmd/internal/objabi/symkind.go
@@ -60,6 +60,13 @@ const (
SDWARFRANGE
SDWARFLOC
SDWARFMISC
+ // ABI alias. An ABI alias symbol is an empty symbol with a
+ // single relocation with 0 size that references the native
+ // function implementation symbol.
+ //
+ // TODO(austin): Remove this and all uses once the compiler
+ // generates real ABI wrappers rather than symbol aliases.
+ SABIALIAS
// Update cmd/link/internal/sym/AbiSymKindToSymKind for new SymKind values.
)
diff --git a/libgo/go/cmd/internal/objabi/symkind_string.go b/libgo/go/cmd/internal/objabi/symkind_string.go
index 7152d6c0069..2b9a9080e8c 100644
--- a/libgo/go/cmd/internal/objabi/symkind_string.go
+++ b/libgo/go/cmd/internal/objabi/symkind_string.go
@@ -4,9 +4,9 @@ package objabi
import "strconv"
-const _SymKind_name = "SxxxSTEXTSRODATASNOPTRDATASDATASBSSSNOPTRBSSSTLSBSSSDWARFINFOSDWARFRANGESDWARFLOCSDWARFMISC"
+const _SymKind_name = "SxxxSTEXTSRODATASNOPTRDATASDATASBSSSNOPTRBSSSTLSBSSSDWARFINFOSDWARFRANGESDWARFLOCSDWARFMISCSABIALIAS"
-var _SymKind_index = [...]uint8{0, 4, 9, 16, 26, 31, 35, 44, 51, 61, 72, 81, 91}
+var _SymKind_index = [...]uint8{0, 4, 9, 16, 26, 31, 35, 44, 51, 61, 72, 81, 91, 100}
func (i SymKind) String() string {
if i >= SymKind(len(_SymKind_index)-1) {
diff --git a/libgo/go/cmd/internal/objabi/util.go b/libgo/go/cmd/internal/objabi/util.go
index a47e2f93a10..da49f706f60 100644
--- a/libgo/go/cmd/internal/objabi/util.go
+++ b/libgo/go/cmd/internal/objabi/util.go
@@ -76,7 +76,7 @@ func init() {
}
func Framepointer_enabled(goos, goarch string) bool {
- return framepointer_enabled != 0 && goarch == "amd64" && goos != "nacl"
+ return framepointer_enabled != 0 && (goarch == "amd64" && goos != "nacl" || goarch == "arm64" && goos == "linux")
}
func addexp(s string) {
@@ -104,8 +104,6 @@ var (
framepointer_enabled int = 1
Fieldtrack_enabled int
Preemptibleloops_enabled int
- Clobberdead_enabled int
- DebugCPU_enabled int
)
// Toolchain experiments.
@@ -119,8 +117,6 @@ var exper = []struct {
{"fieldtrack", &Fieldtrack_enabled},
{"framepointer", &framepointer_enabled},
{"preemptibleloops", &Preemptibleloops_enabled},
- {"clobberdead", &Clobberdead_enabled},
- {"debugcpu", &DebugCPU_enabled},
}
var defaultExpstring = Expstring()
diff --git a/libgo/go/cmd/internal/sys/arch.go b/libgo/go/cmd/internal/sys/arch.go
new file mode 100644
index 00000000000..487c9260e85
--- /dev/null
+++ b/libgo/go/cmd/internal/sys/arch.go
@@ -0,0 +1,187 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sys
+
+import "encoding/binary"
+
+// ArchFamily represents a family of one or more related architectures.
+// For example, amd64 and amd64p32 are both members of the AMD64 family,
+// and ppc64 and ppc64le are both members of the PPC64 family.
+type ArchFamily byte
+
+const (
+ NoArch ArchFamily = iota
+ AMD64
+ ARM
+ ARM64
+ I386
+ MIPS
+ MIPS64
+ PPC64
+ S390X
+ Wasm
+)
+
+// Arch represents an individual architecture.
+type Arch struct {
+ Name string
+ Family ArchFamily
+
+ ByteOrder binary.ByteOrder
+
+ // PtrSize is the size in bytes of pointers and the
+ // predeclared "int", "uint", and "uintptr" types.
+ PtrSize int
+
+ // RegSize is the size in bytes of general purpose registers.
+ RegSize int
+
+ // MinLC is the minimum length of an instruction code.
+ MinLC int
+}
+
+// InFamily reports whether a is a member of any of the specified
+// architecture families.
+func (a *Arch) InFamily(xs ...ArchFamily) bool {
+ for _, x := range xs {
+ if a.Family == x {
+ return true
+ }
+ }
+ return false
+}
+
+var Arch386 = &Arch{
+ Name: "386",
+ Family: I386,
+ ByteOrder: binary.LittleEndian,
+ PtrSize: 4,
+ RegSize: 4,
+ MinLC: 1,
+}
+
+var ArchAMD64 = &Arch{
+ Name: "amd64",
+ Family: AMD64,
+ ByteOrder: binary.LittleEndian,
+ PtrSize: 8,
+ RegSize: 8,
+ MinLC: 1,
+}
+
+var ArchAMD64P32 = &Arch{
+ Name: "amd64p32",
+ Family: AMD64,
+ ByteOrder: binary.LittleEndian,
+ PtrSize: 4,
+ RegSize: 8,
+ MinLC: 1,
+}
+
+var ArchARM = &Arch{
+ Name: "arm",
+ Family: ARM,
+ ByteOrder: binary.LittleEndian,
+ PtrSize: 4,
+ RegSize: 4,
+ MinLC: 4,
+}
+
+var ArchARM64 = &Arch{
+ Name: "arm64",
+ Family: ARM64,
+ ByteOrder: binary.LittleEndian,
+ PtrSize: 8,
+ RegSize: 8,
+ MinLC: 4,
+}
+
+var ArchMIPS = &Arch{
+ Name: "mips",
+ Family: MIPS,
+ ByteOrder: binary.BigEndian,
+ PtrSize: 4,
+ RegSize: 4,
+ MinLC: 4,
+}
+
+var ArchMIPSLE = &Arch{
+ Name: "mipsle",
+ Family: MIPS,
+ ByteOrder: binary.LittleEndian,
+ PtrSize: 4,
+ RegSize: 4,
+ MinLC: 4,
+}
+
+var ArchMIPS64 = &Arch{
+ Name: "mips64",
+ Family: MIPS64,
+ ByteOrder: binary.BigEndian,
+ PtrSize: 8,
+ RegSize: 8,
+ MinLC: 4,
+}
+
+var ArchMIPS64LE = &Arch{
+ Name: "mips64le",
+ Family: MIPS64,
+ ByteOrder: binary.LittleEndian,
+ PtrSize: 8,
+ RegSize: 8,
+ MinLC: 4,
+}
+
+var ArchPPC64 = &Arch{
+ Name: "ppc64",
+ Family: PPC64,
+ ByteOrder: binary.BigEndian,
+ PtrSize: 8,
+ RegSize: 8,
+ MinLC: 4,
+}
+
+var ArchPPC64LE = &Arch{
+ Name: "ppc64le",
+ Family: PPC64,
+ ByteOrder: binary.LittleEndian,
+ PtrSize: 8,
+ RegSize: 8,
+ MinLC: 4,
+}
+
+var ArchS390X = &Arch{
+ Name: "s390x",
+ Family: S390X,
+ ByteOrder: binary.BigEndian,
+ PtrSize: 8,
+ RegSize: 8,
+ MinLC: 2,
+}
+
+var ArchWasm = &Arch{
+ Name: "wasm",
+ Family: Wasm,
+ ByteOrder: binary.LittleEndian,
+ PtrSize: 8,
+ RegSize: 8,
+ MinLC: 1,
+}
+
+var Archs = [...]*Arch{
+ Arch386,
+ ArchAMD64,
+ ArchAMD64P32,
+ ArchARM,
+ ArchARM64,
+ ArchMIPS,
+ ArchMIPSLE,
+ ArchMIPS64,
+ ArchMIPS64LE,
+ ArchPPC64,
+ ArchPPC64LE,
+ ArchS390X,
+ ArchWasm,
+}
diff --git a/libgo/go/cmd/internal/sys/supported.go b/libgo/go/cmd/internal/sys/supported.go
new file mode 100644
index 00000000000..a53da6ed2cb
--- /dev/null
+++ b/libgo/go/cmd/internal/sys/supported.go
@@ -0,0 +1,29 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sys
+
+// RaceDetectorSupported reports whether goos/goarch supports the race
+// detector. There is a copy of this function in cmd/dist/test.go.
+func RaceDetectorSupported(goos, goarch string) bool {
+ switch goos {
+ case "linux":
+ return goarch == "amd64" || goarch == "ppc64le" || goarch == "arm64"
+ case "darwin", "freebsd", "netbsd", "windows":
+ return goarch == "amd64"
+ default:
+ return false
+ }
+}
+
+// MSanSupported reports whether goos/goarch supports the memory
+// sanitizer option. There is a copy of this function in cmd/dist/test.go.
+func MSanSupported(goos, goarch string) bool {
+ switch goos {
+ case "linux":
+ return goarch == "amd64" || goarch == "arm64"
+ default:
+ return false
+ }
+}
diff --git a/libgo/go/cmd/vet/all/main.go b/libgo/go/cmd/vet/all/main.go
index 09181f96895..2500c690bfd 100644
--- a/libgo/go/cmd/vet/all/main.go
+++ b/libgo/go/cmd/vet/all/main.go
@@ -7,6 +7,9 @@
// The vet/all command runs go vet on the standard library and commands.
// It compares the output against a set of whitelists
// maintained in the whitelist directory.
+//
+// This program attempts to build packages from golang.org/x/tools,
+// which must be in your GOPATH.
package main
import (
@@ -18,6 +21,7 @@ import (
"go/types"
"internal/testenv"
"io"
+ "io/ioutil"
"log"
"os"
"os/exec"
@@ -192,9 +196,21 @@ func vetPlatforms(pp []platform) {
}
func (p platform) vet() {
- if p.os == "linux" && p.arch == "riscv64" {
- // TODO(tklauser): enable as soon as the riscv64 port has fully landed
- fmt.Println("skipping linux/riscv64")
+ if p.os == "linux" && (p.arch == "riscv64" || p.arch == "sparc64") {
+ // TODO(tklauser): enable as soon as these ports have fully landed
+ fmt.Printf("skipping %s/%s\n", p.os, p.arch)
+ return
+ }
+
+ if p.os == "windows" && p.arch == "arm" {
+ // TODO(jordanrh1): enable as soon as the windows/arm port has fully landed
+ fmt.Println("skipping windows/arm")
+ return
+ }
+
+ if p.os == "aix" && p.arch == "ppc64" {
+ // TODO(aix): enable as soon as the aix/ppc64 port has fully landed
+ fmt.Println("skipping aix/ppc64")
return
}
@@ -205,13 +221,36 @@ func (p platform) vet() {
w := make(whitelist)
w.load(p.os, p.arch)
- // 'go tool vet .' is considerably faster than 'go vet ./...'
+ tmpdir, err := ioutil.TempDir("", "cmd-vet-all")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+
+ // Build the go/packages-based vet command from the x/tools
+ // repo. It is considerably faster than "go vet", which rebuilds
+ // the standard library.
+ vetTool := filepath.Join(tmpdir, "vet")
+ cmd := exec.Command(cmdGoPath, "build", "-o", vetTool, "golang.org/x/tools/go/analysis/cmd/vet")
+ cmd.Dir = filepath.Join(runtime.GOROOT(), "src")
+ cmd.Stderr = os.Stderr
+ cmd.Stdout = os.Stderr
+ if err := cmd.Run(); err != nil {
+ log.Fatal(err)
+ }
+
// TODO: The unsafeptr checks are disabled for now,
// because there are so many false positives,
// and no clear way to improve vet to eliminate large chunks of them.
// And having them in the whitelists will just cause annoyance
// and churn when working on the runtime.
- cmd := exec.Command(cmdGoPath, "tool", "vet", "-unsafeptr=false", "-source", ".")
+ cmd = exec.Command(vetTool,
+ "-unsafeptr=0",
+ "-nilness=0", // expensive, uses SSA
+ "std",
+ "cmd/...",
+ "cmd/compile/internal/gc/testdata",
+ )
cmd.Dir = filepath.Join(runtime.GOROOT(), "src")
cmd.Env = append(os.Environ(), "GOOS="+p.os, "GOARCH="+p.arch, "CGO_ENABLED=0")
stderr, err := cmd.StderrPipe()
@@ -231,6 +270,9 @@ NextLine:
if strings.HasPrefix(line, "vet: ") {
// Typecheck failure: Malformed syntax or multiple packages or the like.
// This will yield nicer error messages elsewhere, so ignore them here.
+
+ // This includes warnings from asmdecl of the form:
+ // "vet: foo.s:16: [amd64] cannot check cross-package assembly function"
continue
}
@@ -242,22 +284,48 @@ NextLine:
io.Copy(os.Stderr, stderr)
break
}
+ if strings.HasPrefix(line, "# ") {
+ // 'go vet' prefixes the output of each vet invocation by a comment:
+ // # [package]
+ continue
+ }
- fields := strings.SplitN(line, ":", 3)
+ // Parse line.
+ // Assume the part before the first ": "
+ // is the "file:line:col: " information.
+ // TODO(adonovan): parse vet -json output.
var file, lineno, msg string
- switch len(fields) {
- case 2:
- // vet message with no line number
- file, msg = fields[0], fields[1]
- case 3:
- file, lineno, msg = fields[0], fields[1], fields[2]
- default:
+ if i := strings.Index(line, ": "); i >= 0 {
+ msg = line[i+len(": "):]
+
+ words := strings.Split(line[:i], ":")
+ switch len(words) {
+ case 3:
+ _ = words[2] // ignore column
+ fallthrough
+ case 2:
+ lineno = words[1]
+ fallthrough
+ case 1:
+ file = words[0]
+
+ // Make the file name relative to GOROOT/src.
+ if rel, err := filepath.Rel(cmd.Dir, file); err == nil {
+ file = rel
+ }
+ default:
+ // error: too many columns
+ }
+ }
+ if file == "" {
if !parseFailed {
parseFailed = true
fmt.Fprintf(os.Stderr, "failed to parse %s vet output:\n", p)
}
fmt.Fprintln(os.Stderr, line)
+ continue
}
+
msg = strings.TrimSpace(msg)
for _, ignore := range ignorePathPrefixes {
diff --git a/libgo/go/cmd/vet/asmdecl.go b/libgo/go/cmd/vet/asmdecl.go
deleted file mode 100644
index ccf6269f1db..00000000000
--- a/libgo/go/cmd/vet/asmdecl.go
+++ /dev/null
@@ -1,734 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Identify mismatches between assembly files and Go func declarations.
-
-package main
-
-import (
- "bytes"
- "fmt"
- "go/ast"
- "go/build"
- "go/token"
- "go/types"
- "regexp"
- "strconv"
- "strings"
-)
-
-// 'kind' is a kind of assembly variable.
-// The kinds 1, 2, 4, 8 stand for values of that size.
-type asmKind int
-
-// These special kinds are not valid sizes.
-const (
- asmString asmKind = 100 + iota
- asmSlice
- asmArray
- asmInterface
- asmEmptyInterface
- asmStruct
- asmComplex
-)
-
-// An asmArch describes assembly parameters for an architecture
-type asmArch struct {
- name string
- bigEndian bool
- stack string
- lr bool
- // calculated during initialization
- sizes types.Sizes
- intSize int
- ptrSize int
- maxAlign int
-}
-
-// An asmFunc describes the expected variables for a function on a given architecture.
-type asmFunc struct {
- arch *asmArch
- size int // size of all arguments
- vars map[string]*asmVar
- varByOffset map[int]*asmVar
-}
-
-// An asmVar describes a single assembly variable.
-type asmVar struct {
- name string
- kind asmKind
- typ string
- off int
- size int
- inner []*asmVar
-}
-
-var (
- asmArch386 = asmArch{name: "386", bigEndian: false, stack: "SP", lr: false}
- asmArchArm = asmArch{name: "arm", bigEndian: false, stack: "R13", lr: true}
- asmArchArm64 = asmArch{name: "arm64", bigEndian: false, stack: "RSP", lr: true}
- asmArchAmd64 = asmArch{name: "amd64", bigEndian: false, stack: "SP", lr: false}
- asmArchAmd64p32 = asmArch{name: "amd64p32", bigEndian: false, stack: "SP", lr: false}
- asmArchMips = asmArch{name: "mips", bigEndian: true, stack: "R29", lr: true}
- asmArchMipsLE = asmArch{name: "mipsle", bigEndian: false, stack: "R29", lr: true}
- asmArchMips64 = asmArch{name: "mips64", bigEndian: true, stack: "R29", lr: true}
- asmArchMips64LE = asmArch{name: "mips64le", bigEndian: false, stack: "R29", lr: true}
- asmArchPpc64 = asmArch{name: "ppc64", bigEndian: true, stack: "R1", lr: true}
- asmArchPpc64LE = asmArch{name: "ppc64le", bigEndian: false, stack: "R1", lr: true}
- asmArchS390X = asmArch{name: "s390x", bigEndian: true, stack: "R15", lr: true}
- asmArchWasm = asmArch{name: "wasm", bigEndian: false, stack: "SP", lr: false}
-
- arches = []*asmArch{
- &asmArch386,
- &asmArchArm,
- &asmArchArm64,
- &asmArchAmd64,
- &asmArchAmd64p32,
- &asmArchMips,
- &asmArchMipsLE,
- &asmArchMips64,
- &asmArchMips64LE,
- &asmArchPpc64,
- &asmArchPpc64LE,
- &asmArchS390X,
- &asmArchWasm,
- }
-)
-
-func init() {
- for _, arch := range arches {
- arch.sizes = types.SizesFor("gc", arch.name)
- if arch.sizes == nil {
- panic("missing SizesFor for gc/" + arch.name)
- }
- arch.intSize = int(arch.sizes.Sizeof(types.Typ[types.Int]))
- arch.ptrSize = int(arch.sizes.Sizeof(types.Typ[types.UnsafePointer]))
- arch.maxAlign = int(arch.sizes.Alignof(types.Typ[types.Int64]))
- }
-
- registerPkgCheck("asmdecl", asmCheck)
-}
-
-var (
- re = regexp.MustCompile
- asmPlusBuild = re(`//\s+\+build\s+([^\n]+)`)
- asmTEXT = re(`\bTEXT\b(.*)·([^\(]+)\(SB\)(?:\s*,\s*([0-9A-Z|+()]+))?(?:\s*,\s*\$(-?[0-9]+)(?:-([0-9]+))?)?`)
- asmDATA = re(`\b(DATA|GLOBL)\b`)
- asmNamedFP = re(`([a-zA-Z0-9_\xFF-\x{10FFFF}]+)(?:\+([0-9]+))\(FP\)`)
- asmUnnamedFP = re(`[^+\-0-9](([0-9]+)\(FP\))`)
- asmSP = re(`[^+\-0-9](([0-9]+)\(([A-Z0-9]+)\))`)
- asmOpcode = re(`^\s*(?:[A-Z0-9a-z_]+:)?\s*([A-Z]+)\s*([^,]*)(?:,\s*(.*))?`)
- ppc64Suff = re(`([BHWD])(ZU|Z|U|BR)?$`)
-)
-
-func asmCheck(pkg *Package) {
- if vcfg.VetxOnly {
- return
- }
-
- // No work if no assembly files.
- if !pkg.hasFileWithSuffix(".s") {
- return
- }
-
- // Gather declarations. knownFunc[name][arch] is func description.
- knownFunc := make(map[string]map[string]*asmFunc)
-
- for _, f := range pkg.files {
- if f.file != nil {
- for _, decl := range f.file.Decls {
- if decl, ok := decl.(*ast.FuncDecl); ok && decl.Body == nil {
- knownFunc[decl.Name.Name] = f.asmParseDecl(decl)
- }
- }
- }
- }
-
-Files:
- for _, f := range pkg.files {
- if !strings.HasSuffix(f.name, ".s") {
- continue
- }
- Println("Checking file", f.name)
-
- // Determine architecture from file name if possible.
- var arch string
- var archDef *asmArch
- for _, a := range arches {
- if strings.HasSuffix(f.name, "_"+a.name+".s") {
- arch = a.name
- archDef = a
- break
- }
- }
-
- lines := strings.SplitAfter(string(f.content), "\n")
- var (
- fn *asmFunc
- fnName string
- localSize, argSize int
- wroteSP bool
- haveRetArg bool
- retLine []int
- )
-
- flushRet := func() {
- if fn != nil && fn.vars["ret"] != nil && !haveRetArg && len(retLine) > 0 {
- v := fn.vars["ret"]
- for _, line := range retLine {
- f.Badf(token.NoPos, "%s:%d: [%s] %s: RET without writing to %d-byte ret+%d(FP)", f.name, line, arch, fnName, v.size, v.off)
- }
- }
- retLine = nil
- }
- for lineno, line := range lines {
- lineno++
-
- badf := func(format string, args ...interface{}) {
- f.Badf(token.NoPos, "%s:%d: [%s] %s: %s", f.name, lineno, arch, fnName, fmt.Sprintf(format, args...))
- }
-
- if arch == "" {
- // Determine architecture from +build line if possible.
- if m := asmPlusBuild.FindStringSubmatch(line); m != nil {
- // There can be multiple architectures in a single +build line,
- // so accumulate them all and then prefer the one that
- // matches build.Default.GOARCH.
- var archCandidates []*asmArch
- for _, fld := range strings.Fields(m[1]) {
- for _, a := range arches {
- if a.name == fld {
- archCandidates = append(archCandidates, a)
- }
- }
- }
- for _, a := range archCandidates {
- if a.name == build.Default.GOARCH {
- archCandidates = []*asmArch{a}
- break
- }
- }
- if len(archCandidates) > 0 {
- arch = archCandidates[0].name
- archDef = archCandidates[0]
- }
- }
- }
-
- if m := asmTEXT.FindStringSubmatch(line); m != nil {
- flushRet()
- if arch == "" {
- // Arch not specified by filename or build tags.
- // Fall back to build.Default.GOARCH.
- for _, a := range arches {
- if a.name == build.Default.GOARCH {
- arch = a.name
- archDef = a
- break
- }
- }
- if arch == "" {
- f.Warnf(token.NoPos, "%s: cannot determine architecture for assembly file", f.name)
- continue Files
- }
- }
- fnName = m[2]
- if pkgName := strings.TrimSpace(m[1]); pkgName != "" {
- pathParts := strings.Split(pkgName, "∕")
- pkgName = pathParts[len(pathParts)-1]
- if pkgName != f.pkg.path {
- f.Warnf(token.NoPos, "%s:%d: [%s] cannot check cross-package assembly function: %s is in package %s", f.name, lineno, arch, fnName, pkgName)
- fn = nil
- fnName = ""
- continue
- }
- }
- flag := m[3]
- fn = knownFunc[fnName][arch]
- if fn != nil {
- size, _ := strconv.Atoi(m[5])
- if size != fn.size && (flag != "7" && !strings.Contains(flag, "NOSPLIT") || size != 0) {
- badf("wrong argument size %d; expected $...-%d", size, fn.size)
- }
- }
- localSize, _ = strconv.Atoi(m[4])
- localSize += archDef.intSize
- if archDef.lr && !strings.Contains(flag, "NOFRAME") {
- // Account for caller's saved LR
- localSize += archDef.intSize
- }
- argSize, _ = strconv.Atoi(m[5])
- if fn == nil && !strings.Contains(fnName, "<>") {
- badf("function %s missing Go declaration", fnName)
- }
- wroteSP = false
- haveRetArg = false
- continue
- } else if strings.Contains(line, "TEXT") && strings.Contains(line, "SB") {
- // function, but not visible from Go (didn't match asmTEXT), so stop checking
- flushRet()
- fn = nil
- fnName = ""
- continue
- }
-
- if strings.Contains(line, "RET") {
- retLine = append(retLine, lineno)
- }
-
- if fnName == "" {
- continue
- }
-
- if asmDATA.FindStringSubmatch(line) != nil {
- fn = nil
- }
-
- if archDef == nil {
- continue
- }
-
- if strings.Contains(line, ", "+archDef.stack) || strings.Contains(line, ",\t"+archDef.stack) {
- wroteSP = true
- continue
- }
-
- for _, m := range asmSP.FindAllStringSubmatch(line, -1) {
- if m[3] != archDef.stack || wroteSP {
- continue
- }
- off := 0
- if m[1] != "" {
- off, _ = strconv.Atoi(m[2])
- }
- if off >= localSize {
- if fn != nil {
- v := fn.varByOffset[off-localSize]
- if v != nil {
- badf("%s should be %s+%d(FP)", m[1], v.name, off-localSize)
- continue
- }
- }
- if off >= localSize+argSize {
- badf("use of %s points beyond argument frame", m[1])
- continue
- }
- badf("use of %s to access argument frame", m[1])
- }
- }
-
- if fn == nil {
- continue
- }
-
- for _, m := range asmUnnamedFP.FindAllStringSubmatch(line, -1) {
- off, _ := strconv.Atoi(m[2])
- v := fn.varByOffset[off]
- if v != nil {
- badf("use of unnamed argument %s; offset %d is %s+%d(FP)", m[1], off, v.name, v.off)
- } else {
- badf("use of unnamed argument %s", m[1])
- }
- }
-
- for _, m := range asmNamedFP.FindAllStringSubmatch(line, -1) {
- name := m[1]
- off := 0
- if m[2] != "" {
- off, _ = strconv.Atoi(m[2])
- }
- if name == "ret" || strings.HasPrefix(name, "ret_") {
- haveRetArg = true
- }
- v := fn.vars[name]
- if v == nil {
- // Allow argframe+0(FP).
- if name == "argframe" && off == 0 {
- continue
- }
- v = fn.varByOffset[off]
- if v != nil {
- badf("unknown variable %s; offset %d is %s+%d(FP)", name, off, v.name, v.off)
- } else {
- badf("unknown variable %s", name)
- }
- continue
- }
- asmCheckVar(badf, fn, line, m[0], off, v)
- }
- }
- flushRet()
- }
-}
-
-func asmKindForType(t types.Type, size int) asmKind {
- switch t := t.Underlying().(type) {
- case *types.Basic:
- switch t.Kind() {
- case types.String:
- return asmString
- case types.Complex64, types.Complex128:
- return asmComplex
- }
- return asmKind(size)
- case *types.Pointer, *types.Chan, *types.Map, *types.Signature:
- return asmKind(size)
- case *types.Struct:
- return asmStruct
- case *types.Interface:
- if t.Empty() {
- return asmEmptyInterface
- }
- return asmInterface
- case *types.Array:
- return asmArray
- case *types.Slice:
- return asmSlice
- }
- panic("unreachable")
-}
-
-// A component is an assembly-addressable component of a composite type,
-// or a composite type itself.
-type component struct {
- size int
- offset int
- kind asmKind
- typ string
- suffix string // Such as _base for string base, _0_lo for lo half of first element of [1]uint64 on 32 bit machine.
- outer string // The suffix for immediately containing composite type.
-}
-
-func newComponent(suffix string, kind asmKind, typ string, offset, size int, outer string) component {
- return component{suffix: suffix, kind: kind, typ: typ, offset: offset, size: size, outer: outer}
-}
-
-// componentsOfType generates a list of components of type t.
-// For example, given string, the components are the string itself, the base, and the length.
-func componentsOfType(arch *asmArch, t types.Type) []component {
- return appendComponentsRecursive(arch, t, nil, "", 0)
-}
-
-// appendComponentsRecursive implements componentsOfType.
-// Recursion is required to correct handle structs and arrays,
-// which can contain arbitrary other types.
-func appendComponentsRecursive(arch *asmArch, t types.Type, cc []component, suffix string, off int) []component {
- s := t.String()
- size := int(arch.sizes.Sizeof(t))
- kind := asmKindForType(t, size)
- cc = append(cc, newComponent(suffix, kind, s, off, size, suffix))
-
- switch kind {
- case 8:
- if arch.ptrSize == 4 {
- w1, w2 := "lo", "hi"
- if arch.bigEndian {
- w1, w2 = w2, w1
- }
- cc = append(cc, newComponent(suffix+"_"+w1, 4, "half "+s, off, 4, suffix))
- cc = append(cc, newComponent(suffix+"_"+w2, 4, "half "+s, off+4, 4, suffix))
- }
-
- case asmEmptyInterface:
- cc = append(cc, newComponent(suffix+"_type", asmKind(arch.ptrSize), "interface type", off, arch.ptrSize, suffix))
- cc = append(cc, newComponent(suffix+"_data", asmKind(arch.ptrSize), "interface data", off+arch.ptrSize, arch.ptrSize, suffix))
-
- case asmInterface:
- cc = append(cc, newComponent(suffix+"_itable", asmKind(arch.ptrSize), "interface itable", off, arch.ptrSize, suffix))
- cc = append(cc, newComponent(suffix+"_data", asmKind(arch.ptrSize), "interface data", off+arch.ptrSize, arch.ptrSize, suffix))
-
- case asmSlice:
- cc = append(cc, newComponent(suffix+"_base", asmKind(arch.ptrSize), "slice base", off, arch.ptrSize, suffix))
- cc = append(cc, newComponent(suffix+"_len", asmKind(arch.intSize), "slice len", off+arch.ptrSize, arch.intSize, suffix))
- cc = append(cc, newComponent(suffix+"_cap", asmKind(arch.intSize), "slice cap", off+arch.ptrSize+arch.intSize, arch.intSize, suffix))
-
- case asmString:
- cc = append(cc, newComponent(suffix+"_base", asmKind(arch.ptrSize), "string base", off, arch.ptrSize, suffix))
- cc = append(cc, newComponent(suffix+"_len", asmKind(arch.intSize), "string len", off+arch.ptrSize, arch.intSize, suffix))
-
- case asmComplex:
- fsize := size / 2
- cc = append(cc, newComponent(suffix+"_real", asmKind(fsize), fmt.Sprintf("real(complex%d)", size*8), off, fsize, suffix))
- cc = append(cc, newComponent(suffix+"_imag", asmKind(fsize), fmt.Sprintf("imag(complex%d)", size*8), off+fsize, fsize, suffix))
-
- case asmStruct:
- tu := t.Underlying().(*types.Struct)
- fields := make([]*types.Var, tu.NumFields())
- for i := 0; i < tu.NumFields(); i++ {
- fields[i] = tu.Field(i)
- }
- offsets := arch.sizes.Offsetsof(fields)
- for i, f := range fields {
- cc = appendComponentsRecursive(arch, f.Type(), cc, suffix+"_"+f.Name(), off+int(offsets[i]))
- }
-
- case asmArray:
- tu := t.Underlying().(*types.Array)
- elem := tu.Elem()
- // Calculate offset of each element array.
- fields := []*types.Var{
- types.NewVar(token.NoPos, nil, "fake0", elem),
- types.NewVar(token.NoPos, nil, "fake1", elem),
- }
- offsets := arch.sizes.Offsetsof(fields)
- elemoff := int(offsets[1])
- for i := 0; i < int(tu.Len()); i++ {
- cc = appendComponentsRecursive(arch, elem, cc, suffix+"_"+strconv.Itoa(i), i*elemoff)
- }
- }
-
- return cc
-}
-
-// asmParseDecl parses a function decl for expected assembly variables.
-func (f *File) asmParseDecl(decl *ast.FuncDecl) map[string]*asmFunc {
- var (
- arch *asmArch
- fn *asmFunc
- offset int
- )
-
- // addParams adds asmVars for each of the parameters in list.
- // isret indicates whether the list are the arguments or the return values.
- addParams := func(list []*ast.Field, isret bool) {
- argnum := 0
- for _, fld := range list {
- t := f.pkg.types[fld.Type].Type
- align := int(arch.sizes.Alignof(t))
- size := int(arch.sizes.Sizeof(t))
- offset += -offset & (align - 1)
- cc := componentsOfType(arch, t)
-
- // names is the list of names with this type.
- names := fld.Names
- if len(names) == 0 {
- // Anonymous args will be called arg, arg1, arg2, ...
- // Similarly so for return values: ret, ret1, ret2, ...
- name := "arg"
- if isret {
- name = "ret"
- }
- if argnum > 0 {
- name += strconv.Itoa(argnum)
- }
- names = []*ast.Ident{ast.NewIdent(name)}
- }
- argnum += len(names)
-
- // Create variable for each name.
- for _, id := range names {
- name := id.Name
- for _, c := range cc {
- outer := name + c.outer
- v := asmVar{
- name: name + c.suffix,
- kind: c.kind,
- typ: c.typ,
- off: offset + c.offset,
- size: c.size,
- }
- if vo := fn.vars[outer]; vo != nil {
- vo.inner = append(vo.inner, &v)
- }
- fn.vars[v.name] = &v
- for i := 0; i < v.size; i++ {
- fn.varByOffset[v.off+i] = &v
- }
- }
- offset += size
- }
- }
- }
-
- m := make(map[string]*asmFunc)
- for _, arch = range arches {
- fn = &asmFunc{
- arch: arch,
- vars: make(map[string]*asmVar),
- varByOffset: make(map[int]*asmVar),
- }
- offset = 0
- addParams(decl.Type.Params.List, false)
- if decl.Type.Results != nil && len(decl.Type.Results.List) > 0 {
- offset += -offset & (arch.maxAlign - 1)
- addParams(decl.Type.Results.List, true)
- }
- fn.size = offset
- m[arch.name] = fn
- }
-
- return m
-}
-
-// asmCheckVar checks a single variable reference.
-func asmCheckVar(badf func(string, ...interface{}), fn *asmFunc, line, expr string, off int, v *asmVar) {
- m := asmOpcode.FindStringSubmatch(line)
- if m == nil {
- if !strings.HasPrefix(strings.TrimSpace(line), "//") {
- badf("cannot find assembly opcode")
- }
- return
- }
-
- // Determine operand sizes from instruction.
- // Typically the suffix suffices, but there are exceptions.
- var src, dst, kind asmKind
- op := m[1]
- switch fn.arch.name + "." + op {
- case "386.FMOVLP":
- src, dst = 8, 4
- case "arm.MOVD":
- src = 8
- case "arm.MOVW":
- src = 4
- case "arm.MOVH", "arm.MOVHU":
- src = 2
- case "arm.MOVB", "arm.MOVBU":
- src = 1
- // LEA* opcodes don't really read the second arg.
- // They just take the address of it.
- case "386.LEAL":
- dst = 4
- case "amd64.LEAQ":
- dst = 8
- case "amd64p32.LEAL":
- dst = 4
- default:
- switch fn.arch.name {
- case "386", "amd64":
- if strings.HasPrefix(op, "F") && (strings.HasSuffix(op, "D") || strings.HasSuffix(op, "DP")) {
- // FMOVDP, FXCHD, etc
- src = 8
- break
- }
- if strings.HasPrefix(op, "P") && strings.HasSuffix(op, "RD") {
- // PINSRD, PEXTRD, etc
- src = 4
- break
- }
- if strings.HasPrefix(op, "F") && (strings.HasSuffix(op, "F") || strings.HasSuffix(op, "FP")) {
- // FMOVFP, FXCHF, etc
- src = 4
- break
- }
- if strings.HasSuffix(op, "SD") {
- // MOVSD, SQRTSD, etc
- src = 8
- break
- }
- if strings.HasSuffix(op, "SS") {
- // MOVSS, SQRTSS, etc
- src = 4
- break
- }
- if strings.HasPrefix(op, "SET") {
- // SETEQ, etc
- src = 1
- break
- }
- switch op[len(op)-1] {
- case 'B':
- src = 1
- case 'W':
- src = 2
- case 'L':
- src = 4
- case 'D', 'Q':
- src = 8
- }
- case "ppc64", "ppc64le":
- // Strip standard suffixes to reveal size letter.
- m := ppc64Suff.FindStringSubmatch(op)
- if m != nil {
- switch m[1][0] {
- case 'B':
- src = 1
- case 'H':
- src = 2
- case 'W':
- src = 4
- case 'D':
- src = 8
- }
- }
- case "mips", "mipsle", "mips64", "mips64le":
- switch op {
- case "MOVB", "MOVBU":
- src = 1
- case "MOVH", "MOVHU":
- src = 2
- case "MOVW", "MOVWU", "MOVF":
- src = 4
- case "MOVV", "MOVD":
- src = 8
- }
- case "s390x":
- switch op {
- case "MOVB", "MOVBZ":
- src = 1
- case "MOVH", "MOVHZ":
- src = 2
- case "MOVW", "MOVWZ", "FMOVS":
- src = 4
- case "MOVD", "FMOVD":
- src = 8
- }
- }
- }
- if dst == 0 {
- dst = src
- }
-
- // Determine whether the match we're holding
- // is the first or second argument.
- if strings.Index(line, expr) > strings.Index(line, ",") {
- kind = dst
- } else {
- kind = src
- }
-
- vk := v.kind
- vs := v.size
- vt := v.typ
- switch vk {
- case asmInterface, asmEmptyInterface, asmString, asmSlice:
- // allow reference to first word (pointer)
- vk = v.inner[0].kind
- vs = v.inner[0].size
- vt = v.inner[0].typ
- }
-
- if off != v.off {
- var inner bytes.Buffer
- for i, vi := range v.inner {
- if len(v.inner) > 1 {
- fmt.Fprintf(&inner, ",")
- }
- fmt.Fprintf(&inner, " ")
- if i == len(v.inner)-1 {
- fmt.Fprintf(&inner, "or ")
- }
- fmt.Fprintf(&inner, "%s+%d(FP)", vi.name, vi.off)
- }
- badf("invalid offset %s; expected %s+%d(FP)%s", expr, v.name, v.off, inner.String())
- return
- }
- if kind != 0 && kind != vk {
- var inner bytes.Buffer
- if len(v.inner) > 0 {
- fmt.Fprintf(&inner, " containing")
- for i, vi := range v.inner {
- if i > 0 && len(v.inner) > 2 {
- fmt.Fprintf(&inner, ",")
- }
- fmt.Fprintf(&inner, " ")
- if i > 0 && i == len(v.inner)-1 {
- fmt.Fprintf(&inner, "and ")
- }
- fmt.Fprintf(&inner, "%s+%d(FP)", vi.name, vi.off)
- }
- }
- badf("invalid %s of %s; %s is %d-byte value%s", op, expr, vt, vs, inner.String())
- }
-}
diff --git a/libgo/go/cmd/vet/assign.go b/libgo/go/cmd/vet/assign.go
deleted file mode 100644
index 223e80d4007..00000000000
--- a/libgo/go/cmd/vet/assign.go
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-This file contains the code to check for useless assignments.
-*/
-
-package main
-
-import (
- "go/ast"
- "go/token"
- "reflect"
-)
-
-func init() {
- register("assign",
- "check for useless assignments",
- checkAssignStmt,
- assignStmt)
-}
-
-// TODO: should also check for assignments to struct fields inside methods
-// that are on T instead of *T.
-
-// checkAssignStmt checks for assignments of the form "<expr> = <expr>".
-// These are almost always useless, and even when they aren't they are usually a mistake.
-func checkAssignStmt(f *File, node ast.Node) {
- stmt := node.(*ast.AssignStmt)
- if stmt.Tok != token.ASSIGN {
- return // ignore :=
- }
- if len(stmt.Lhs) != len(stmt.Rhs) {
- // If LHS and RHS have different cardinality, they can't be the same.
- return
- }
- for i, lhs := range stmt.Lhs {
- rhs := stmt.Rhs[i]
- if hasSideEffects(f, lhs) || hasSideEffects(f, rhs) {
- continue // expressions may not be equal
- }
- if reflect.TypeOf(lhs) != reflect.TypeOf(rhs) {
- continue // short-circuit the heavy-weight gofmt check
- }
- le := f.gofmt(lhs)
- re := f.gofmt(rhs)
- if le == re {
- f.Badf(stmt.Pos(), "self-assignment of %s to %s", re, le)
- }
- }
-}
diff --git a/libgo/go/cmd/vet/atomic.go b/libgo/go/cmd/vet/atomic.go
deleted file mode 100644
index b425669e1ae..00000000000
--- a/libgo/go/cmd/vet/atomic.go
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "go/ast"
- "go/token"
- "go/types"
-)
-
-func init() {
- register("atomic",
- "check for common mistaken usages of the sync/atomic package",
- checkAtomicAssignment,
- assignStmt)
-}
-
-// checkAtomicAssignment walks the assignment statement checking for common
-// mistaken usage of atomic package, such as: x = atomic.AddUint64(&x, 1)
-func checkAtomicAssignment(f *File, node ast.Node) {
- n := node.(*ast.AssignStmt)
- if len(n.Lhs) != len(n.Rhs) {
- return
- }
- if len(n.Lhs) == 1 && n.Tok == token.DEFINE {
- return
- }
-
- for i, right := range n.Rhs {
- call, ok := right.(*ast.CallExpr)
- if !ok {
- continue
- }
- sel, ok := call.Fun.(*ast.SelectorExpr)
- if !ok {
- continue
- }
- pkgIdent, _ := sel.X.(*ast.Ident)
- pkgName, ok := f.pkg.uses[pkgIdent].(*types.PkgName)
- if !ok || pkgName.Imported().Path() != "sync/atomic" {
- continue
- }
-
- switch sel.Sel.Name {
- case "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr":
- f.checkAtomicAddAssignment(n.Lhs[i], call)
- }
- }
-}
-
-// checkAtomicAddAssignment walks the atomic.Add* method calls checking for assigning the return value
-// to the same variable being used in the operation
-func (f *File) checkAtomicAddAssignment(left ast.Expr, call *ast.CallExpr) {
- if len(call.Args) != 2 {
- return
- }
- arg := call.Args[0]
- broken := false
-
- if uarg, ok := arg.(*ast.UnaryExpr); ok && uarg.Op == token.AND {
- broken = f.gofmt(left) == f.gofmt(uarg.X)
- } else if star, ok := left.(*ast.StarExpr); ok {
- broken = f.gofmt(star.X) == f.gofmt(arg)
- }
-
- if broken {
- f.Bad(left.Pos(), "direct assignment to atomic value")
- }
-}
diff --git a/libgo/go/cmd/vet/bool.go b/libgo/go/cmd/vet/bool.go
deleted file mode 100644
index 1cd477f988c..00000000000
--- a/libgo/go/cmd/vet/bool.go
+++ /dev/null
@@ -1,197 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file contains boolean condition tests.
-
-package main
-
-import (
- "go/ast"
- "go/token"
-)
-
-func init() {
- register("bool",
- "check for mistakes involving boolean operators",
- checkBool,
- binaryExpr)
-}
-
-func checkBool(f *File, n ast.Node) {
- e := n.(*ast.BinaryExpr)
-
- var op boolOp
- switch e.Op {
- case token.LOR:
- op = or
- case token.LAND:
- op = and
- default:
- return
- }
-
- comm := op.commutativeSets(f, e)
- for _, exprs := range comm {
- op.checkRedundant(f, exprs)
- op.checkSuspect(f, exprs)
- }
-}
-
-type boolOp struct {
- name string
- tok token.Token // token corresponding to this operator
- badEq token.Token // token corresponding to the equality test that should not be used with this operator
-}
-
-var (
- or = boolOp{"or", token.LOR, token.NEQ}
- and = boolOp{"and", token.LAND, token.EQL}
-)
-
-// commutativeSets returns all side effect free sets of
-// expressions in e that are connected by op.
-// For example, given 'a || b || f() || c || d' with the or op,
-// commutativeSets returns {{b, a}, {d, c}}.
-func (op boolOp) commutativeSets(f *File, e *ast.BinaryExpr) [][]ast.Expr {
- exprs := op.split(e)
-
- // Partition the slice of expressions into commutative sets.
- i := 0
- var sets [][]ast.Expr
- for j := 0; j <= len(exprs); j++ {
- if j == len(exprs) || hasSideEffects(f, exprs[j]) {
- if i < j {
- sets = append(sets, exprs[i:j])
- }
- i = j + 1
- }
- }
-
- return sets
-}
-
-// checkRedundant checks for expressions of the form
-// e && e
-// e || e
-// Exprs must contain only side effect free expressions.
-func (op boolOp) checkRedundant(f *File, exprs []ast.Expr) {
- seen := make(map[string]bool)
- for _, e := range exprs {
- efmt := f.gofmt(e)
- if seen[efmt] {
- f.Badf(e.Pos(), "redundant %s: %s %s %s", op.name, efmt, op.tok, efmt)
- } else {
- seen[efmt] = true
- }
- }
-}
-
-// checkSuspect checks for expressions of the form
-// x != c1 || x != c2
-// x == c1 && x == c2
-// where c1 and c2 are constant expressions.
-// If c1 and c2 are the same then it's redundant;
-// if c1 and c2 are different then it's always true or always false.
-// Exprs must contain only side effect free expressions.
-func (op boolOp) checkSuspect(f *File, exprs []ast.Expr) {
- // seen maps from expressions 'x' to equality expressions 'x != c'.
- seen := make(map[string]string)
-
- for _, e := range exprs {
- bin, ok := e.(*ast.BinaryExpr)
- if !ok || bin.Op != op.badEq {
- continue
- }
-
- // In order to avoid false positives, restrict to cases
- // in which one of the operands is constant. We're then
- // interested in the other operand.
- // In the rare case in which both operands are constant
- // (e.g. runtime.GOOS and "windows"), we'll only catch
- // mistakes if the LHS is repeated, which is how most
- // code is written.
- var x ast.Expr
- switch {
- case f.pkg.types[bin.Y].Value != nil:
- x = bin.X
- case f.pkg.types[bin.X].Value != nil:
- x = bin.Y
- default:
- continue
- }
-
- // e is of the form 'x != c' or 'x == c'.
- xfmt := f.gofmt(x)
- efmt := f.gofmt(e)
- if prev, found := seen[xfmt]; found {
- // checkRedundant handles the case in which efmt == prev.
- if efmt != prev {
- f.Badf(e.Pos(), "suspect %s: %s %s %s", op.name, efmt, op.tok, prev)
- }
- } else {
- seen[xfmt] = efmt
- }
- }
-}
-
-// hasSideEffects reports whether evaluation of e has side effects.
-func hasSideEffects(f *File, e ast.Expr) bool {
- safe := true
- ast.Inspect(e, func(node ast.Node) bool {
- switch n := node.(type) {
- case *ast.CallExpr:
- typVal := f.pkg.types[n.Fun]
- switch {
- case typVal.IsType():
- // Type conversion, which is safe.
- case typVal.IsBuiltin():
- // Builtin func, conservatively assumed to not
- // be safe for now.
- safe = false
- return false
- default:
- // A non-builtin func or method call.
- // Conservatively assume that all of them have
- // side effects for now.
- safe = false
- return false
- }
- case *ast.UnaryExpr:
- if n.Op == token.ARROW {
- safe = false
- return false
- }
- }
- return true
- })
- return !safe
-}
-
-// split returns a slice of all subexpressions in e that are connected by op.
-// For example, given 'a || (b || c) || d' with the or op,
-// split returns []{d, c, b, a}.
-func (op boolOp) split(e ast.Expr) (exprs []ast.Expr) {
- for {
- e = unparen(e)
- if b, ok := e.(*ast.BinaryExpr); ok && b.Op == op.tok {
- exprs = append(exprs, op.split(b.Y)...)
- e = b.X
- } else {
- exprs = append(exprs, e)
- break
- }
- }
- return
-}
-
-// unparen returns e with any enclosing parentheses stripped.
-func unparen(e ast.Expr) ast.Expr {
- for {
- p, ok := e.(*ast.ParenExpr)
- if !ok {
- return e
- }
- e = p.X
- }
-}
diff --git a/libgo/go/cmd/vet/buildtag.go b/libgo/go/cmd/vet/buildtag.go
deleted file mode 100644
index ba3a361b911..00000000000
--- a/libgo/go/cmd/vet/buildtag.go
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "bytes"
- "fmt"
- "os"
- "strings"
- "unicode"
-)
-
-var (
- nl = []byte("\n")
- slashSlash = []byte("//")
- plusBuild = []byte("+build")
-)
-
-func badfLine(f *File, line int, format string, args ...interface{}) {
- msg := fmt.Sprintf(format, args...)
- fmt.Fprintf(os.Stderr, "%s:%d: %s\n", f.name, line, msg)
- setExit(1)
-}
-
-// checkBuildTag checks that build tags are in the correct location and well-formed.
-func checkBuildTag(f *File) {
- if !vet("buildtags") {
- return
- }
-
- // we must look at the raw lines, as build tags may appear in non-Go
- // files such as assembly files.
- lines := bytes.SplitAfter(f.content, nl)
-
- // lineWithComment reports whether a line corresponds to a comment in
- // the source file. If the source file wasn't Go, the function always
- // returns true.
- lineWithComment := func(line int) bool {
- if f.file == nil {
- // Current source file is not Go, so be conservative.
- return true
- }
- for _, group := range f.file.Comments {
- startLine := f.fset.Position(group.Pos()).Line
- endLine := f.fset.Position(group.End()).Line
- if startLine <= line && line <= endLine {
- return true
- }
- }
- return false
- }
-
- // Determine cutpoint where +build comments are no longer valid.
- // They are valid in leading // comments in the file followed by
- // a blank line.
- var cutoff int
- for i, line := range lines {
- line = bytes.TrimSpace(line)
- if len(line) == 0 {
- cutoff = i
- continue
- }
- if bytes.HasPrefix(line, slashSlash) {
- continue
- }
- break
- }
-
- for i, line := range lines {
- line = bytes.TrimSpace(line)
- if !bytes.HasPrefix(line, slashSlash) {
- continue
- }
- if !bytes.Contains(line, plusBuild) {
- // Check that the comment contains "+build" early, to
- // avoid unnecessary lineWithComment calls that may
- // incur linear searches.
- continue
- }
- if !lineWithComment(i + 1) {
- // This is a line in a Go source file that looks like a
- // comment, but actually isn't - such as part of a raw
- // string.
- continue
- }
-
- text := bytes.TrimSpace(line[2:])
- if bytes.HasPrefix(text, plusBuild) {
- fields := bytes.Fields(text)
- if !bytes.Equal(fields[0], plusBuild) {
- // Comment is something like +buildasdf not +build.
- badfLine(f, i+1, "possible malformed +build comment")
- continue
- }
- if i >= cutoff {
- badfLine(f, i+1, "+build comment must appear before package clause and be followed by a blank line")
- continue
- }
- // Check arguments.
- Args:
- for _, arg := range fields[1:] {
- for _, elem := range strings.Split(string(arg), ",") {
- if strings.HasPrefix(elem, "!!") {
- badfLine(f, i+1, "invalid double negative in build constraint: %s", arg)
- break Args
- }
- elem = strings.TrimPrefix(elem, "!")
- for _, c := range elem {
- if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' {
- badfLine(f, i+1, "invalid non-alphanumeric build constraint: %s", arg)
- break Args
- }
- }
- }
- }
- continue
- }
- // Comment with +build but not at beginning.
- if i < cutoff {
- badfLine(f, i+1, "possible malformed +build comment")
- continue
- }
- }
-}
diff --git a/libgo/go/cmd/vet/cgo.go b/libgo/go/cmd/vet/cgo.go
deleted file mode 100644
index 76364ff6ed8..00000000000
--- a/libgo/go/cmd/vet/cgo.go
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Check for invalid cgo pointer passing.
-// This looks for code that uses cgo to call C code passing values
-// whose types are almost always invalid according to the cgo pointer
-// sharing rules.
-// Specifically, it warns about attempts to pass a Go chan, map, func,
-// or slice to C, either directly, or via a pointer, array, or struct.
-
-package main
-
-import (
- "go/ast"
- "go/token"
- "go/types"
-)
-
-func init() {
- register("cgocall",
- "check for types that may not be passed to cgo calls",
- checkCgoCall,
- callExpr)
-}
-
-func checkCgoCall(f *File, node ast.Node) {
- x := node.(*ast.CallExpr)
-
- // We are only looking for calls to functions imported from
- // the "C" package.
- sel, ok := x.Fun.(*ast.SelectorExpr)
- if !ok {
- return
- }
- id, ok := sel.X.(*ast.Ident)
- if !ok {
- return
- }
-
- pkgname, ok := f.pkg.uses[id].(*types.PkgName)
- if !ok || pkgname.Imported().Path() != "C" {
- return
- }
-
- // A call to C.CBytes passes a pointer but is always safe.
- if sel.Sel.Name == "CBytes" {
- return
- }
-
- for _, arg := range x.Args {
- if !typeOKForCgoCall(cgoBaseType(f, arg), make(map[types.Type]bool)) {
- f.Badf(arg.Pos(), "possibly passing Go type with embedded pointer to C")
- }
-
- // Check for passing the address of a bad type.
- if conv, ok := arg.(*ast.CallExpr); ok && len(conv.Args) == 1 && f.hasBasicType(conv.Fun, types.UnsafePointer) {
- arg = conv.Args[0]
- }
- if u, ok := arg.(*ast.UnaryExpr); ok && u.Op == token.AND {
- if !typeOKForCgoCall(cgoBaseType(f, u.X), make(map[types.Type]bool)) {
- f.Badf(arg.Pos(), "possibly passing Go type with embedded pointer to C")
- }
- }
- }
-}
-
-// cgoBaseType tries to look through type conversions involving
-// unsafe.Pointer to find the real type. It converts:
-// unsafe.Pointer(x) => x
-// *(*unsafe.Pointer)(unsafe.Pointer(&x)) => x
-func cgoBaseType(f *File, arg ast.Expr) types.Type {
- switch arg := arg.(type) {
- case *ast.CallExpr:
- if len(arg.Args) == 1 && f.hasBasicType(arg.Fun, types.UnsafePointer) {
- return cgoBaseType(f, arg.Args[0])
- }
- case *ast.StarExpr:
- call, ok := arg.X.(*ast.CallExpr)
- if !ok || len(call.Args) != 1 {
- break
- }
- // Here arg is *f(v).
- t := f.pkg.types[call.Fun].Type
- if t == nil {
- break
- }
- ptr, ok := t.Underlying().(*types.Pointer)
- if !ok {
- break
- }
- // Here arg is *(*p)(v)
- elem, ok := ptr.Elem().Underlying().(*types.Basic)
- if !ok || elem.Kind() != types.UnsafePointer {
- break
- }
- // Here arg is *(*unsafe.Pointer)(v)
- call, ok = call.Args[0].(*ast.CallExpr)
- if !ok || len(call.Args) != 1 {
- break
- }
- // Here arg is *(*unsafe.Pointer)(f(v))
- if !f.hasBasicType(call.Fun, types.UnsafePointer) {
- break
- }
- // Here arg is *(*unsafe.Pointer)(unsafe.Pointer(v))
- u, ok := call.Args[0].(*ast.UnaryExpr)
- if !ok || u.Op != token.AND {
- break
- }
- // Here arg is *(*unsafe.Pointer)(unsafe.Pointer(&v))
- return cgoBaseType(f, u.X)
- }
-
- return f.pkg.types[arg].Type
-}
-
-// typeOKForCgoCall reports whether the type of arg is OK to pass to a
-// C function using cgo. This is not true for Go types with embedded
-// pointers. m is used to avoid infinite recursion on recursive types.
-func typeOKForCgoCall(t types.Type, m map[types.Type]bool) bool {
- if t == nil || m[t] {
- return true
- }
- m[t] = true
- switch t := t.Underlying().(type) {
- case *types.Chan, *types.Map, *types.Signature, *types.Slice:
- return false
- case *types.Pointer:
- return typeOKForCgoCall(t.Elem(), m)
- case *types.Array:
- return typeOKForCgoCall(t.Elem(), m)
- case *types.Struct:
- for i := 0; i < t.NumFields(); i++ {
- if !typeOKForCgoCall(t.Field(i).Type(), m) {
- return false
- }
- }
- }
- return true
-}
diff --git a/libgo/go/cmd/vet/composite.go b/libgo/go/cmd/vet/composite.go
deleted file mode 100644
index 861e040aac4..00000000000
--- a/libgo/go/cmd/vet/composite.go
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file contains the test for unkeyed struct literals.
-
-package main
-
-import (
- "cmd/vet/internal/whitelist"
- "flag"
- "go/ast"
- "go/types"
- "strings"
-)
-
-var compositeWhiteList = flag.Bool("compositewhitelist", true, "use composite white list; for testing only")
-
-func init() {
- register("composites",
- "check that composite literals of types from imported packages use field-keyed elements",
- checkUnkeyedLiteral,
- compositeLit)
-}
-
-// checkUnkeyedLiteral checks if a composite literal is a struct literal with
-// unkeyed fields.
-func checkUnkeyedLiteral(f *File, node ast.Node) {
- cl := node.(*ast.CompositeLit)
-
- typ := f.pkg.types[cl].Type
- if typ == nil {
- // cannot determine composite literals' type, skip it
- return
- }
- typeName := typ.String()
- if *compositeWhiteList && whitelist.UnkeyedLiteral[typeName] {
- // skip whitelisted types
- return
- }
- under := typ.Underlying()
- for {
- ptr, ok := under.(*types.Pointer)
- if !ok {
- break
- }
- under = ptr.Elem().Underlying()
- }
- if _, ok := under.(*types.Struct); !ok {
- // skip non-struct composite literals
- return
- }
- if isLocalType(f, typ) {
- // allow unkeyed locally defined composite literal
- return
- }
-
- // check if the CompositeLit contains an unkeyed field
- allKeyValue := true
- for _, e := range cl.Elts {
- if _, ok := e.(*ast.KeyValueExpr); !ok {
- allKeyValue = false
- break
- }
- }
- if allKeyValue {
- // all the composite literal fields are keyed
- return
- }
-
- f.Badf(cl.Pos(), "%s composite literal uses unkeyed fields", typeName)
-}
-
-func isLocalType(f *File, typ types.Type) bool {
- switch x := typ.(type) {
- case *types.Struct:
- // struct literals are local types
- return true
- case *types.Pointer:
- return isLocalType(f, x.Elem())
- case *types.Named:
- // names in package foo are local to foo_test too
- return strings.TrimSuffix(x.Obj().Pkg().Path(), "_test") == strings.TrimSuffix(f.pkg.path, "_test")
- }
- return false
-}
diff --git a/libgo/go/cmd/vet/copylock.go b/libgo/go/cmd/vet/copylock.go
deleted file mode 100644
index ed88ca89603..00000000000
--- a/libgo/go/cmd/vet/copylock.go
+++ /dev/null
@@ -1,266 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file contains the code to check that locks are not passed by value.
-
-package main
-
-import (
- "bytes"
- "fmt"
- "go/ast"
- "go/token"
- "go/types"
-)
-
-func init() {
- register("copylocks",
- "check that locks are not passed by value",
- checkCopyLocks,
- funcDecl, rangeStmt, funcLit, callExpr, assignStmt, genDecl, compositeLit, returnStmt)
-}
-
-// checkCopyLocks checks whether node might
-// inadvertently copy a lock.
-func checkCopyLocks(f *File, node ast.Node) {
- switch node := node.(type) {
- case *ast.RangeStmt:
- checkCopyLocksRange(f, node)
- case *ast.FuncDecl:
- checkCopyLocksFunc(f, node.Name.Name, node.Recv, node.Type)
- case *ast.FuncLit:
- checkCopyLocksFunc(f, "func", nil, node.Type)
- case *ast.CallExpr:
- checkCopyLocksCallExpr(f, node)
- case *ast.AssignStmt:
- checkCopyLocksAssign(f, node)
- case *ast.GenDecl:
- checkCopyLocksGenDecl(f, node)
- case *ast.CompositeLit:
- checkCopyLocksCompositeLit(f, node)
- case *ast.ReturnStmt:
- checkCopyLocksReturnStmt(f, node)
- }
-}
-
-// checkCopyLocksAssign checks whether an assignment
-// copies a lock.
-func checkCopyLocksAssign(f *File, as *ast.AssignStmt) {
- for i, x := range as.Rhs {
- if path := lockPathRhs(f, x); path != nil {
- f.Badf(x.Pos(), "assignment copies lock value to %v: %v", f.gofmt(as.Lhs[i]), path)
- }
- }
-}
-
-// checkCopyLocksGenDecl checks whether lock is copied
-// in variable declaration.
-func checkCopyLocksGenDecl(f *File, gd *ast.GenDecl) {
- if gd.Tok != token.VAR {
- return
- }
- for _, spec := range gd.Specs {
- valueSpec := spec.(*ast.ValueSpec)
- for i, x := range valueSpec.Values {
- if path := lockPathRhs(f, x); path != nil {
- f.Badf(x.Pos(), "variable declaration copies lock value to %v: %v", valueSpec.Names[i].Name, path)
- }
- }
- }
-}
-
-// checkCopyLocksCompositeLit detects lock copy inside a composite literal
-func checkCopyLocksCompositeLit(f *File, cl *ast.CompositeLit) {
- for _, x := range cl.Elts {
- if node, ok := x.(*ast.KeyValueExpr); ok {
- x = node.Value
- }
- if path := lockPathRhs(f, x); path != nil {
- f.Badf(x.Pos(), "literal copies lock value from %v: %v", f.gofmt(x), path)
- }
- }
-}
-
-// checkCopyLocksReturnStmt detects lock copy in return statement
-func checkCopyLocksReturnStmt(f *File, rs *ast.ReturnStmt) {
- for _, x := range rs.Results {
- if path := lockPathRhs(f, x); path != nil {
- f.Badf(x.Pos(), "return copies lock value: %v", path)
- }
- }
-}
-
-// checkCopyLocksCallExpr detects lock copy in the arguments to a function call
-func checkCopyLocksCallExpr(f *File, ce *ast.CallExpr) {
- var id *ast.Ident
- switch fun := ce.Fun.(type) {
- case *ast.Ident:
- id = fun
- case *ast.SelectorExpr:
- id = fun.Sel
- }
- if fun, ok := f.pkg.uses[id].(*types.Builtin); ok {
- switch fun.Name() {
- case "new", "len", "cap", "Sizeof":
- return
- }
- }
- for _, x := range ce.Args {
- if path := lockPathRhs(f, x); path != nil {
- f.Badf(x.Pos(), "call of %s copies lock value: %v", f.gofmt(ce.Fun), path)
- }
- }
-}
-
-// checkCopyLocksFunc checks whether a function might
-// inadvertently copy a lock, by checking whether
-// its receiver, parameters, or return values
-// are locks.
-func checkCopyLocksFunc(f *File, name string, recv *ast.FieldList, typ *ast.FuncType) {
- if recv != nil && len(recv.List) > 0 {
- expr := recv.List[0].Type
- if path := lockPath(f.pkg.typesPkg, f.pkg.types[expr].Type); path != nil {
- f.Badf(expr.Pos(), "%s passes lock by value: %v", name, path)
- }
- }
-
- if typ.Params != nil {
- for _, field := range typ.Params.List {
- expr := field.Type
- if path := lockPath(f.pkg.typesPkg, f.pkg.types[expr].Type); path != nil {
- f.Badf(expr.Pos(), "%s passes lock by value: %v", name, path)
- }
- }
- }
-
- // Don't check typ.Results. If T has a Lock field it's OK to write
- // return T{}
- // because that is returning the zero value. Leave result checking
- // to the return statement.
-}
-
-// checkCopyLocksRange checks whether a range statement
-// might inadvertently copy a lock by checking whether
-// any of the range variables are locks.
-func checkCopyLocksRange(f *File, r *ast.RangeStmt) {
- checkCopyLocksRangeVar(f, r.Tok, r.Key)
- checkCopyLocksRangeVar(f, r.Tok, r.Value)
-}
-
-func checkCopyLocksRangeVar(f *File, rtok token.Token, e ast.Expr) {
- if e == nil {
- return
- }
- id, isId := e.(*ast.Ident)
- if isId && id.Name == "_" {
- return
- }
-
- var typ types.Type
- if rtok == token.DEFINE {
- if !isId {
- return
- }
- obj := f.pkg.defs[id]
- if obj == nil {
- return
- }
- typ = obj.Type()
- } else {
- typ = f.pkg.types[e].Type
- }
-
- if typ == nil {
- return
- }
- if path := lockPath(f.pkg.typesPkg, typ); path != nil {
- f.Badf(e.Pos(), "range var %s copies lock: %v", f.gofmt(e), path)
- }
-}
-
-type typePath []types.Type
-
-// String pretty-prints a typePath.
-func (path typePath) String() string {
- n := len(path)
- var buf bytes.Buffer
- for i := range path {
- if i > 0 {
- fmt.Fprint(&buf, " contains ")
- }
- // The human-readable path is in reverse order, outermost to innermost.
- fmt.Fprint(&buf, path[n-i-1].String())
- }
- return buf.String()
-}
-
-func lockPathRhs(f *File, x ast.Expr) typePath {
- if _, ok := x.(*ast.CompositeLit); ok {
- return nil
- }
- if _, ok := x.(*ast.CallExpr); ok {
- // A call may return a zero value.
- return nil
- }
- if star, ok := x.(*ast.StarExpr); ok {
- if _, ok := star.X.(*ast.CallExpr); ok {
- // A call may return a pointer to a zero value.
- return nil
- }
- }
- return lockPath(f.pkg.typesPkg, f.pkg.types[x].Type)
-}
-
-// lockPath returns a typePath describing the location of a lock value
-// contained in typ. If there is no contained lock, it returns nil.
-func lockPath(tpkg *types.Package, typ types.Type) typePath {
- if typ == nil {
- return nil
- }
-
- for {
- atyp, ok := typ.Underlying().(*types.Array)
- if !ok {
- break
- }
- typ = atyp.Elem()
- }
-
- // We're only interested in the case in which the underlying
- // type is a struct. (Interfaces and pointers are safe to copy.)
- styp, ok := typ.Underlying().(*types.Struct)
- if !ok {
- return nil
- }
-
- // We're looking for cases in which a pointer to this type
- // is a sync.Locker, but a value is not. This differentiates
- // embedded interfaces from embedded values.
- if types.Implements(types.NewPointer(typ), lockerType) && !types.Implements(typ, lockerType) {
- return []types.Type{typ}
- }
-
- nfields := styp.NumFields()
- for i := 0; i < nfields; i++ {
- ftyp := styp.Field(i).Type()
- subpath := lockPath(tpkg, ftyp)
- if subpath != nil {
- return append(subpath, typ)
- }
- }
-
- return nil
-}
-
-var lockerType *types.Interface
-
-// Construct a sync.Locker interface type.
-func init() {
- nullary := types.NewSignature(nil, nil, nil, false) // func()
- methods := []*types.Func{
- types.NewFunc(token.NoPos, nil, "Lock", nullary),
- types.NewFunc(token.NoPos, nil, "Unlock", nullary),
- }
- lockerType = types.NewInterface(methods, nil).Complete()
-}
diff --git a/libgo/go/cmd/vet/dead.go b/libgo/go/cmd/vet/dead.go
deleted file mode 100644
index 0facec55258..00000000000
--- a/libgo/go/cmd/vet/dead.go
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2017 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-//
-// Simplified dead code detector. Used for skipping certain checks
-// on unreachable code (for instance, shift checks on arch-specific code).
-
-package main
-
-import (
- "go/ast"
- "go/constant"
-)
-
-// updateDead puts unreachable "if" and "case" nodes into f.dead.
-func (f *File) updateDead(node ast.Node) {
- if f.dead[node] {
- // The node is already marked as dead.
- return
- }
-
- switch stmt := node.(type) {
- case *ast.IfStmt:
- // "if" branch is dead if its condition evaluates
- // to constant false.
- v := f.pkg.types[stmt.Cond].Value
- if v == nil {
- return
- }
- if !constant.BoolVal(v) {
- f.setDead(stmt.Body)
- return
- }
- f.setDead(stmt.Else)
- case *ast.SwitchStmt:
- // Case clause with empty switch tag is dead if it evaluates
- // to constant false.
- if stmt.Tag == nil {
- BodyLoopBool:
- for _, stmt := range stmt.Body.List {
- cc := stmt.(*ast.CaseClause)
- if cc.List == nil {
- // Skip default case.
- continue
- }
- for _, expr := range cc.List {
- v := f.pkg.types[expr].Value
- if v == nil || v.Kind() != constant.Bool || constant.BoolVal(v) {
- continue BodyLoopBool
- }
- }
- f.setDead(cc)
- }
- return
- }
-
- // Case clause is dead if its constant value doesn't match
- // the constant value from the switch tag.
- // TODO: This handles integer comparisons only.
- v := f.pkg.types[stmt.Tag].Value
- if v == nil || v.Kind() != constant.Int {
- return
- }
- tagN, ok := constant.Uint64Val(v)
- if !ok {
- return
- }
- BodyLoopInt:
- for _, x := range stmt.Body.List {
- cc := x.(*ast.CaseClause)
- if cc.List == nil {
- // Skip default case.
- continue
- }
- for _, expr := range cc.List {
- v := f.pkg.types[expr].Value
- if v == nil {
- continue BodyLoopInt
- }
- n, ok := constant.Uint64Val(v)
- if !ok || tagN == n {
- continue BodyLoopInt
- }
- }
- f.setDead(cc)
- }
- }
-}
-
-// setDead marks the node and all the children as dead.
-func (f *File) setDead(node ast.Node) {
- dv := deadVisitor{
- f: f,
- }
- ast.Walk(dv, node)
-}
-
-type deadVisitor struct {
- f *File
-}
-
-func (dv deadVisitor) Visit(node ast.Node) ast.Visitor {
- if node == nil {
- return nil
- }
- dv.f.dead[node] = true
- return dv
-}
diff --git a/libgo/go/cmd/vet/deadcode.go b/libgo/go/cmd/vet/deadcode.go
deleted file mode 100644
index b1077aef38f..00000000000
--- a/libgo/go/cmd/vet/deadcode.go
+++ /dev/null
@@ -1,298 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Check for syntactically unreachable code.
-
-package main
-
-import (
- "go/ast"
- "go/token"
-)
-
-func init() {
- register("unreachable",
- "check for unreachable code",
- checkUnreachable,
- funcDecl, funcLit)
-}
-
-type deadState struct {
- f *File
- hasBreak map[ast.Stmt]bool
- hasGoto map[string]bool
- labels map[string]ast.Stmt
- breakTarget ast.Stmt
-
- reachable bool
-}
-
-// checkUnreachable checks a function body for dead code.
-//
-// TODO(adonovan): use the new cfg package, which is more precise.
-func checkUnreachable(f *File, node ast.Node) {
- var body *ast.BlockStmt
- switch n := node.(type) {
- case *ast.FuncDecl:
- body = n.Body
- case *ast.FuncLit:
- body = n.Body
- }
- if body == nil {
- return
- }
-
- d := &deadState{
- f: f,
- hasBreak: make(map[ast.Stmt]bool),
- hasGoto: make(map[string]bool),
- labels: make(map[string]ast.Stmt),
- }
-
- d.findLabels(body)
-
- d.reachable = true
- d.findDead(body)
-}
-
-// findLabels gathers information about the labels defined and used by stmt
-// and about which statements break, whether a label is involved or not.
-func (d *deadState) findLabels(stmt ast.Stmt) {
- switch x := stmt.(type) {
- default:
- d.f.Warnf(x.Pos(), "internal error in findLabels: unexpected statement %T", x)
-
- case *ast.AssignStmt,
- *ast.BadStmt,
- *ast.DeclStmt,
- *ast.DeferStmt,
- *ast.EmptyStmt,
- *ast.ExprStmt,
- *ast.GoStmt,
- *ast.IncDecStmt,
- *ast.ReturnStmt,
- *ast.SendStmt:
- // no statements inside
-
- case *ast.BlockStmt:
- for _, stmt := range x.List {
- d.findLabels(stmt)
- }
-
- case *ast.BranchStmt:
- switch x.Tok {
- case token.GOTO:
- if x.Label != nil {
- d.hasGoto[x.Label.Name] = true
- }
-
- case token.BREAK:
- stmt := d.breakTarget
- if x.Label != nil {
- stmt = d.labels[x.Label.Name]
- }
- if stmt != nil {
- d.hasBreak[stmt] = true
- }
- }
-
- case *ast.IfStmt:
- d.findLabels(x.Body)
- if x.Else != nil {
- d.findLabels(x.Else)
- }
-
- case *ast.LabeledStmt:
- d.labels[x.Label.Name] = x.Stmt
- d.findLabels(x.Stmt)
-
- // These cases are all the same, but the x.Body only works
- // when the specific type of x is known, so the cases cannot
- // be merged.
- case *ast.ForStmt:
- outer := d.breakTarget
- d.breakTarget = x
- d.findLabels(x.Body)
- d.breakTarget = outer
-
- case *ast.RangeStmt:
- outer := d.breakTarget
- d.breakTarget = x
- d.findLabels(x.Body)
- d.breakTarget = outer
-
- case *ast.SelectStmt:
- outer := d.breakTarget
- d.breakTarget = x
- d.findLabels(x.Body)
- d.breakTarget = outer
-
- case *ast.SwitchStmt:
- outer := d.breakTarget
- d.breakTarget = x
- d.findLabels(x.Body)
- d.breakTarget = outer
-
- case *ast.TypeSwitchStmt:
- outer := d.breakTarget
- d.breakTarget = x
- d.findLabels(x.Body)
- d.breakTarget = outer
-
- case *ast.CommClause:
- for _, stmt := range x.Body {
- d.findLabels(stmt)
- }
-
- case *ast.CaseClause:
- for _, stmt := range x.Body {
- d.findLabels(stmt)
- }
- }
-}
-
-// findDead walks the statement looking for dead code.
-// If d.reachable is false on entry, stmt itself is dead.
-// When findDead returns, d.reachable tells whether the
-// statement following stmt is reachable.
-func (d *deadState) findDead(stmt ast.Stmt) {
- // Is this a labeled goto target?
- // If so, assume it is reachable due to the goto.
- // This is slightly conservative, in that we don't
- // check that the goto is reachable, so
- // L: goto L
- // will not provoke a warning.
- // But it's good enough.
- if x, isLabel := stmt.(*ast.LabeledStmt); isLabel && d.hasGoto[x.Label.Name] {
- d.reachable = true
- }
-
- if !d.reachable {
- switch stmt.(type) {
- case *ast.EmptyStmt:
- // do not warn about unreachable empty statements
- default:
- d.f.Bad(stmt.Pos(), "unreachable code")
- d.reachable = true // silence error about next statement
- }
- }
-
- switch x := stmt.(type) {
- default:
- d.f.Warnf(x.Pos(), "internal error in findDead: unexpected statement %T", x)
-
- case *ast.AssignStmt,
- *ast.BadStmt,
- *ast.DeclStmt,
- *ast.DeferStmt,
- *ast.EmptyStmt,
- *ast.GoStmt,
- *ast.IncDecStmt,
- *ast.SendStmt:
- // no control flow
-
- case *ast.BlockStmt:
- for _, stmt := range x.List {
- d.findDead(stmt)
- }
-
- case *ast.BranchStmt:
- switch x.Tok {
- case token.BREAK, token.GOTO, token.FALLTHROUGH:
- d.reachable = false
- case token.CONTINUE:
- // NOTE: We accept "continue" statements as terminating.
- // They are not necessary in the spec definition of terminating,
- // because a continue statement cannot be the final statement
- // before a return. But for the more general problem of syntactically
- // identifying dead code, continue redirects control flow just
- // like the other terminating statements.
- d.reachable = false
- }
-
- case *ast.ExprStmt:
- // Call to panic?
- call, ok := x.X.(*ast.CallExpr)
- if ok {
- name, ok := call.Fun.(*ast.Ident)
- if ok && name.Name == "panic" && name.Obj == nil {
- d.reachable = false
- }
- }
-
- case *ast.ForStmt:
- d.findDead(x.Body)
- d.reachable = x.Cond != nil || d.hasBreak[x]
-
- case *ast.IfStmt:
- d.findDead(x.Body)
- if x.Else != nil {
- r := d.reachable
- d.reachable = true
- d.findDead(x.Else)
- d.reachable = d.reachable || r
- } else {
- // might not have executed if statement
- d.reachable = true
- }
-
- case *ast.LabeledStmt:
- d.findDead(x.Stmt)
-
- case *ast.RangeStmt:
- d.findDead(x.Body)
- d.reachable = true
-
- case *ast.ReturnStmt:
- d.reachable = false
-
- case *ast.SelectStmt:
- // NOTE: Unlike switch and type switch below, we don't care
- // whether a select has a default, because a select without a
- // default blocks until one of the cases can run. That's different
- // from a switch without a default, which behaves like it has
- // a default with an empty body.
- anyReachable := false
- for _, comm := range x.Body.List {
- d.reachable = true
- for _, stmt := range comm.(*ast.CommClause).Body {
- d.findDead(stmt)
- }
- anyReachable = anyReachable || d.reachable
- }
- d.reachable = anyReachable || d.hasBreak[x]
-
- case *ast.SwitchStmt:
- anyReachable := false
- hasDefault := false
- for _, cas := range x.Body.List {
- cc := cas.(*ast.CaseClause)
- if cc.List == nil {
- hasDefault = true
- }
- d.reachable = true
- for _, stmt := range cc.Body {
- d.findDead(stmt)
- }
- anyReachable = anyReachable || d.reachable
- }
- d.reachable = anyReachable || d.hasBreak[x] || !hasDefault
-
- case *ast.TypeSwitchStmt:
- anyReachable := false
- hasDefault := false
- for _, cas := range x.Body.List {
- cc := cas.(*ast.CaseClause)
- if cc.List == nil {
- hasDefault = true
- }
- d.reachable = true
- for _, stmt := range cc.Body {
- d.findDead(stmt)
- }
- anyReachable = anyReachable || d.reachable
- }
- d.reachable = anyReachable || d.hasBreak[x] || !hasDefault
- }
-}
diff --git a/libgo/go/cmd/vet/doc.go b/libgo/go/cmd/vet/doc.go
index d9af0a88759..279d081be39 100644
--- a/libgo/go/cmd/vet/doc.go
+++ b/libgo/go/cmd/vet/doc.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors. All rights reserved.
+// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -9,211 +9,63 @@ calls whose arguments do not align with the format string. Vet uses heuristics
that do not guarantee all reports are genuine problems, but it can find errors
not caught by the compilers.
-Vet is normally invoked using the go command by running "go vet":
+Vet is normally invoked through the go command.
+This command vets the package in the current directory:
go vet
-vets the package in the current directory.
- go vet package/path/name
-vets the package whose path is provided.
+whereas this one vets the packages whose path is provided:
+
+ go vet my/project/...
Use "go help packages" to see other ways of specifying which packages to vet.
-Vet's exit code is 2 for erroneous invocation of the tool, 1 if a
+Vet's exit code is non-zero for erroneous invocation of the tool or if a
problem was reported, and 0 otherwise. Note that the tool does not
-check every possible problem and depends on unreliable heuristics
+check every possible problem and depends on unreliable heuristics,
so it should be used as guidance only, not as a firm indicator of
program correctness.
-By default the -all flag is set so all checks are performed.
-If any flags are explicitly set to true, only those tests are run. Conversely, if
-any flag is explicitly set to false, only those tests are disabled. Thus -printf=true
-runs the printf check, -printf=false runs all checks except the printf check.
-
-By default vet uses the object files generated by 'go install some/pkg' to typecheck the code.
-If the -source flag is provided, vet uses only source code.
-
-Available checks:
-
-Assembly declarations
-
-Flag: -asmdecl
-
-Mismatches between assembly files and Go function declarations.
-
-Useless assignments
-
-Flag: -assign
-
-Check for useless assignments.
-
-Atomic mistakes
-
-Flag: -atomic
-
-Common mistaken usages of the sync/atomic package.
-
-Boolean conditions
-
-Flag: -bool
-
-Mistakes involving boolean operators.
-
-Build tags
-
-Flag: -buildtags
-
-Badly formed or misplaced +build tags.
-
-Invalid uses of cgo
-
-Flag: -cgocall
-
-Detect some violations of the cgo pointer passing rules.
-
-Unkeyed composite literals
-
-Flag: -composites
-
-Composite struct literals that do not use the field-keyed syntax.
-
-Copying locks
-
-Flag: -copylocks
-
-Locks that are erroneously passed by value.
-
-HTTP responses used incorrectly
-
-Flag: -httpresponse
-
-Mistakes deferring a function call on an HTTP response before
-checking whether the error returned with the response was nil.
-
-Failure to call the cancelation function returned by WithCancel
-
-Flag: -lostcancel
-
-The cancelation function returned by context.WithCancel, WithTimeout,
-and WithDeadline must be called or the new context will remain live
-until its parent context is cancelled.
-(The background context is never cancelled.)
-
-Methods
-
-Flag: -methods
-
-Non-standard signatures for methods with familiar names, including:
- Format GobEncode GobDecode MarshalJSON MarshalXML
- Peek ReadByte ReadFrom ReadRune Scan Seek
- UnmarshalJSON UnreadByte UnreadRune WriteByte
- WriteTo
-
-Nil function comparison
-
-Flag: -nilfunc
-
-Comparisons between functions and nil.
-
-Printf family
-
-Flag: -printf
-
-Suspicious calls to fmt.Print, fmt.Printf, and related functions.
-The check applies to known functions (for example, those in package fmt)
-as well as any detected wrappers of known functions.
-
-The -printfuncs flag specifies a comma-separated list of names of
-additional known formatting functions. Each name can be of the form
-pkg.Name or pkg.Type.Name, where pkg is a complete import path,
-or else can be a case-insensitive unqualified identifier like "errorf".
-If a listed name ends in f, the function is assumed to be Printf-like,
-taking a format string before the argument list. Otherwise it is
-assumed to be Print-like, taking a list of arguments with no format string.
-
-Range loop variables
-
-Flag: -rangeloops
-
-Incorrect uses of range loop variables in closures.
-
-Shadowed variables
-
-Flag: -shadow=false (experimental; must be set explicitly)
-
-Variables that may have been unintentionally shadowed.
-
-Shifts
-
-Flag: -shift
-
-Shifts equal to or longer than the variable's length.
-
-Struct tags
-
-Flag: -structtags
-
-Struct tags that do not follow the format understood by reflect.StructTag.Get.
-Well-known encoding struct tags (json, xml) used with unexported fields.
-
-Tests and documentation examples
-
-Flag: -tests
-
-Mistakes involving tests including functions with incorrect names or signatures
-and example tests that document identifiers not in the package.
-
-Unreachable code
-
-Flag: -unreachable
-
-Unreachable code.
-
-Misuse of unsafe Pointers
-
-Flag: -unsafeptr
-
-Likely incorrect uses of unsafe.Pointer to convert integers to pointers.
-A conversion from uintptr to unsafe.Pointer is invalid if it implies that
-there is a uintptr-typed word in memory that holds a pointer value,
-because that word will be invisible to stack copying and to the garbage
-collector.
-
-Unused result of certain function calls
-
-Flag: -unusedresult
-
-Calls to well-known functions and methods that return a value that is
-discarded. By default, this includes functions like fmt.Errorf and
-fmt.Sprintf and methods like String and Error. The flags -unusedfuncs
-and -unusedstringmethods control the set.
-
-Other flags
-
-These flags configure the behavior of vet:
-
- -all (default true)
- Enable all non-experimental checks.
- -v
- Verbose mode
- -printfuncs
- A comma-separated list of print-like function names
- to supplement the standard list.
- For more information, see the discussion of the -printf flag.
- -shadowstrict
- Whether to be strict about shadowing; can be noisy.
-
-Using vet directly
-
-For testing and debugging vet can be run directly by invoking
-"go tool vet" or just running the binary. Run this way, vet might not
-have up to date information for imported packages.
-
- go tool vet source/directory/*.go
-vets the files named, all of which must be in the same package.
-
- go tool vet source/directory
-recursively descends the directory, vetting each package it finds.
+To list the available checks, run "go tool vet help":
+
+ asmdecl report mismatches between assembly files and Go declarations
+ assign check for useless assignments
+ atomic check for common mistakes using the sync/atomic package
+ bools check for common mistakes involving boolean operators
+ buildtag check that +build tags are well-formed and correctly located
+ cgocall detect some violations of the cgo pointer passing rules
+ composites check for unkeyed composite literals
+ copylocks check for locks erroneously passed by value
+ httpresponse check for mistakes using HTTP responses
+ loopclosure check references to loop variables from within nested functions
+ lostcancel check cancel func returned by context.WithCancel is called
+ nilfunc check for useless comparisons between functions and nil
+ printf check consistency of Printf format strings and arguments
+ shift check for shifts that equal or exceed the width of the integer
+ stdmethods check signature of methods of well-known interfaces
+ structtag check that struct field tags conform to reflect.StructTag.Get
+ tests check for common mistaken usages of tests and examples
+ unmarshal report passing non-pointer or non-interface values to unmarshal
+ unreachable check for unreachable code
+ unsafeptr check for invalid conversions of uintptr to unsafe.Pointer
+ unusedresult check for unused results of calls to some functions
+
+For details and flags of a particular check, such as printf, run "go tool vet help printf".
+
+By default, all checks are performed.
+If any flags are explicitly set to true, only those tests are run.
+Conversely, if any flag is explicitly set to false, only those tests are disabled.
+Thus -printf=true runs the printf check,
+and -printf=false runs all checks except the printf check.
+
+For information on writing a new check, see golang.org/x/tools/go/analysis.
+
+Core flags:
+
+ -c=N
+ display offending line plus N lines of surrounding context
+ -json
+ emit analysis diagnostics (and errors) in JSON format
*/
package main
diff --git a/libgo/go/cmd/vet/httpresponse.go b/libgo/go/cmd/vet/httpresponse.go
deleted file mode 100644
index 791d11d5bde..00000000000
--- a/libgo/go/cmd/vet/httpresponse.go
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file contains the check for http.Response values being used before
-// checking for errors.
-
-package main
-
-import (
- "go/ast"
- "go/types"
-)
-
-func init() {
- register("httpresponse",
- "check errors are checked before using an http Response",
- checkHTTPResponse, callExpr)
-}
-
-func checkHTTPResponse(f *File, node ast.Node) {
- call := node.(*ast.CallExpr)
- if !isHTTPFuncOrMethodOnClient(f, call) {
- return // the function call is not related to this check.
- }
-
- finder := &blockStmtFinder{node: call}
- ast.Walk(finder, f.file)
- stmts := finder.stmts()
- if len(stmts) < 2 {
- return // the call to the http function is the last statement of the block.
- }
-
- asg, ok := stmts[0].(*ast.AssignStmt)
- if !ok {
- return // the first statement is not assignment.
- }
- resp := rootIdent(asg.Lhs[0])
- if resp == nil {
- return // could not find the http.Response in the assignment.
- }
-
- def, ok := stmts[1].(*ast.DeferStmt)
- if !ok {
- return // the following statement is not a defer.
- }
- root := rootIdent(def.Call.Fun)
- if root == nil {
- return // could not find the receiver of the defer call.
- }
-
- if resp.Obj == root.Obj {
- f.Badf(root.Pos(), "using %s before checking for errors", resp.Name)
- }
-}
-
-// isHTTPFuncOrMethodOnClient checks whether the given call expression is on
-// either a function of the net/http package or a method of http.Client that
-// returns (*http.Response, error).
-func isHTTPFuncOrMethodOnClient(f *File, expr *ast.CallExpr) bool {
- fun, _ := expr.Fun.(*ast.SelectorExpr)
- sig, _ := f.pkg.types[fun].Type.(*types.Signature)
- if sig == nil {
- return false // the call is not on of the form x.f()
- }
-
- res := sig.Results()
- if res.Len() != 2 {
- return false // the function called does not return two values.
- }
- if ptr, ok := res.At(0).Type().(*types.Pointer); !ok || !isNamedType(ptr.Elem(), "net/http", "Response") {
- return false // the first return type is not *http.Response.
- }
- if !types.Identical(res.At(1).Type().Underlying(), errorType) {
- return false // the second return type is not error
- }
-
- typ := f.pkg.types[fun.X].Type
- if typ == nil {
- id, ok := fun.X.(*ast.Ident)
- return ok && id.Name == "http" // function in net/http package.
- }
-
- if isNamedType(typ, "net/http", "Client") {
- return true // method on http.Client.
- }
- ptr, ok := typ.(*types.Pointer)
- return ok && isNamedType(ptr.Elem(), "net/http", "Client") // method on *http.Client.
-}
-
-// blockStmtFinder is an ast.Visitor that given any ast node can find the
-// statement containing it and its succeeding statements in the same block.
-type blockStmtFinder struct {
- node ast.Node // target of search
- stmt ast.Stmt // innermost statement enclosing argument to Visit
- block *ast.BlockStmt // innermost block enclosing argument to Visit.
-}
-
-// Visit finds f.node performing a search down the ast tree.
-// It keeps the last block statement and statement seen for later use.
-func (f *blockStmtFinder) Visit(node ast.Node) ast.Visitor {
- if node == nil || f.node.Pos() < node.Pos() || f.node.End() > node.End() {
- return nil // not here
- }
- switch n := node.(type) {
- case *ast.BlockStmt:
- f.block = n
- case ast.Stmt:
- f.stmt = n
- }
- if f.node.Pos() == node.Pos() && f.node.End() == node.End() {
- return nil // found
- }
- return f // keep looking
-}
-
-// stmts returns the statements of f.block starting from the one including f.node.
-func (f *blockStmtFinder) stmts() []ast.Stmt {
- for i, v := range f.block.List {
- if f.stmt == v {
- return f.block.List[i:]
- }
- }
- return nil
-}
-
-// rootIdent finds the root identifier x in a chain of selections x.y.z, or nil if not found.
-func rootIdent(n ast.Node) *ast.Ident {
- switch n := n.(type) {
- case *ast.SelectorExpr:
- return rootIdent(n.X)
- case *ast.Ident:
- return n
- default:
- return nil
- }
-}
diff --git a/libgo/go/cmd/vet/internal/cfg/builder.go b/libgo/go/cmd/vet/internal/cfg/builder.go
deleted file mode 100644
index da1cc7e6384..00000000000
--- a/libgo/go/cmd/vet/internal/cfg/builder.go
+++ /dev/null
@@ -1,512 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package cfg
-
-// This file implements the CFG construction pass.
-
-import (
- "fmt"
- "go/ast"
- "go/token"
-)
-
-type builder struct {
- cfg *CFG
- mayReturn func(*ast.CallExpr) bool
- current *Block
- lblocks map[*ast.Object]*lblock // labeled blocks
- targets *targets // linked stack of branch targets
-}
-
-func (b *builder) stmt(_s ast.Stmt) {
- // The label of the current statement. If non-nil, its _goto
- // target is always set; its _break and _continue are set only
- // within the body of switch/typeswitch/select/for/range.
- // It is effectively an additional default-nil parameter of stmt().
- var label *lblock
-start:
- switch s := _s.(type) {
- case *ast.BadStmt,
- *ast.SendStmt,
- *ast.IncDecStmt,
- *ast.GoStmt,
- *ast.DeferStmt,
- *ast.EmptyStmt,
- *ast.AssignStmt:
- // No effect on control flow.
- b.add(s)
-
- case *ast.ExprStmt:
- b.add(s)
- if call, ok := s.X.(*ast.CallExpr); ok && !b.mayReturn(call) {
- // Calls to panic, os.Exit, etc, never return.
- b.current = b.newUnreachableBlock("unreachable.call")
- }
-
- case *ast.DeclStmt:
- // Treat each var ValueSpec as a separate statement.
- d := s.Decl.(*ast.GenDecl)
- if d.Tok == token.VAR {
- for _, spec := range d.Specs {
- if spec, ok := spec.(*ast.ValueSpec); ok {
- b.add(spec)
- }
- }
- }
-
- case *ast.LabeledStmt:
- label = b.labeledBlock(s.Label)
- b.jump(label._goto)
- b.current = label._goto
- _s = s.Stmt
- goto start // effectively: tailcall stmt(g, s.Stmt, label)
-
- case *ast.ReturnStmt:
- b.add(s)
- b.current = b.newUnreachableBlock("unreachable.return")
-
- case *ast.BranchStmt:
- var block *Block
- switch s.Tok {
- case token.BREAK:
- if s.Label != nil {
- if lb := b.labeledBlock(s.Label); lb != nil {
- block = lb._break
- }
- } else {
- for t := b.targets; t != nil && block == nil; t = t.tail {
- block = t._break
- }
- }
-
- case token.CONTINUE:
- if s.Label != nil {
- if lb := b.labeledBlock(s.Label); lb != nil {
- block = lb._continue
- }
- } else {
- for t := b.targets; t != nil && block == nil; t = t.tail {
- block = t._continue
- }
- }
-
- case token.FALLTHROUGH:
- for t := b.targets; t != nil; t = t.tail {
- block = t._fallthrough
- }
-
- case token.GOTO:
- if s.Label != nil {
- block = b.labeledBlock(s.Label)._goto
- }
- }
- if block == nil {
- block = b.newBlock("undefined.branch")
- }
- b.jump(block)
- b.current = b.newUnreachableBlock("unreachable.branch")
-
- case *ast.BlockStmt:
- b.stmtList(s.List)
-
- case *ast.IfStmt:
- if s.Init != nil {
- b.stmt(s.Init)
- }
- then := b.newBlock("if.then")
- done := b.newBlock("if.done")
- _else := done
- if s.Else != nil {
- _else = b.newBlock("if.else")
- }
- b.add(s.Cond)
- b.ifelse(then, _else)
- b.current = then
- b.stmt(s.Body)
- b.jump(done)
-
- if s.Else != nil {
- b.current = _else
- b.stmt(s.Else)
- b.jump(done)
- }
-
- b.current = done
-
- case *ast.SwitchStmt:
- b.switchStmt(s, label)
-
- case *ast.TypeSwitchStmt:
- b.typeSwitchStmt(s, label)
-
- case *ast.SelectStmt:
- b.selectStmt(s, label)
-
- case *ast.ForStmt:
- b.forStmt(s, label)
-
- case *ast.RangeStmt:
- b.rangeStmt(s, label)
-
- default:
- panic(fmt.Sprintf("unexpected statement kind: %T", s))
- }
-}
-
-func (b *builder) stmtList(list []ast.Stmt) {
- for _, s := range list {
- b.stmt(s)
- }
-}
-
-func (b *builder) switchStmt(s *ast.SwitchStmt, label *lblock) {
- if s.Init != nil {
- b.stmt(s.Init)
- }
- if s.Tag != nil {
- b.add(s.Tag)
- }
- done := b.newBlock("switch.done")
- if label != nil {
- label._break = done
- }
- // We pull the default case (if present) down to the end.
- // But each fallthrough label must point to the next
- // body block in source order, so we preallocate a
- // body block (fallthru) for the next case.
- // Unfortunately this makes for a confusing block order.
- var defaultBody *[]ast.Stmt
- var defaultFallthrough *Block
- var fallthru, defaultBlock *Block
- ncases := len(s.Body.List)
- for i, clause := range s.Body.List {
- body := fallthru
- if body == nil {
- body = b.newBlock("switch.body") // first case only
- }
-
- // Preallocate body block for the next case.
- fallthru = done
- if i+1 < ncases {
- fallthru = b.newBlock("switch.body")
- }
-
- cc := clause.(*ast.CaseClause)
- if cc.List == nil {
- // Default case.
- defaultBody = &cc.Body
- defaultFallthrough = fallthru
- defaultBlock = body
- continue
- }
-
- var nextCond *Block
- for _, cond := range cc.List {
- nextCond = b.newBlock("switch.next")
- b.add(cond) // one half of the tag==cond condition
- b.ifelse(body, nextCond)
- b.current = nextCond
- }
- b.current = body
- b.targets = &targets{
- tail: b.targets,
- _break: done,
- _fallthrough: fallthru,
- }
- b.stmtList(cc.Body)
- b.targets = b.targets.tail
- b.jump(done)
- b.current = nextCond
- }
- if defaultBlock != nil {
- b.jump(defaultBlock)
- b.current = defaultBlock
- b.targets = &targets{
- tail: b.targets,
- _break: done,
- _fallthrough: defaultFallthrough,
- }
- b.stmtList(*defaultBody)
- b.targets = b.targets.tail
- }
- b.jump(done)
- b.current = done
-}
-
-func (b *builder) typeSwitchStmt(s *ast.TypeSwitchStmt, label *lblock) {
- if s.Init != nil {
- b.stmt(s.Init)
- }
- if s.Assign != nil {
- b.add(s.Assign)
- }
-
- done := b.newBlock("typeswitch.done")
- if label != nil {
- label._break = done
- }
- var default_ *ast.CaseClause
- for _, clause := range s.Body.List {
- cc := clause.(*ast.CaseClause)
- if cc.List == nil {
- default_ = cc
- continue
- }
- body := b.newBlock("typeswitch.body")
- var next *Block
- for _, casetype := range cc.List {
- next = b.newBlock("typeswitch.next")
- // casetype is a type, so don't call b.add(casetype).
- // This block logically contains a type assertion,
- // x.(casetype), but it's unclear how to represent x.
- _ = casetype
- b.ifelse(body, next)
- b.current = next
- }
- b.current = body
- b.typeCaseBody(cc, done)
- b.current = next
- }
- if default_ != nil {
- b.typeCaseBody(default_, done)
- } else {
- b.jump(done)
- }
- b.current = done
-}
-
-func (b *builder) typeCaseBody(cc *ast.CaseClause, done *Block) {
- b.targets = &targets{
- tail: b.targets,
- _break: done,
- }
- b.stmtList(cc.Body)
- b.targets = b.targets.tail
- b.jump(done)
-}
-
-func (b *builder) selectStmt(s *ast.SelectStmt, label *lblock) {
- // First evaluate channel expressions.
- // TODO(adonovan): fix: evaluate only channel exprs here.
- for _, clause := range s.Body.List {
- if comm := clause.(*ast.CommClause).Comm; comm != nil {
- b.stmt(comm)
- }
- }
-
- done := b.newBlock("select.done")
- if label != nil {
- label._break = done
- }
-
- var defaultBody *[]ast.Stmt
- for _, cc := range s.Body.List {
- clause := cc.(*ast.CommClause)
- if clause.Comm == nil {
- defaultBody = &clause.Body
- continue
- }
- body := b.newBlock("select.body")
- next := b.newBlock("select.next")
- b.ifelse(body, next)
- b.current = body
- b.targets = &targets{
- tail: b.targets,
- _break: done,
- }
- switch comm := clause.Comm.(type) {
- case *ast.ExprStmt: // <-ch
- // nop
- case *ast.AssignStmt: // x := <-states[state].Chan
- b.add(comm.Lhs[0])
- }
- b.stmtList(clause.Body)
- b.targets = b.targets.tail
- b.jump(done)
- b.current = next
- }
- if defaultBody != nil {
- b.targets = &targets{
- tail: b.targets,
- _break: done,
- }
- b.stmtList(*defaultBody)
- b.targets = b.targets.tail
- b.jump(done)
- }
- b.current = done
-}
-
-func (b *builder) forStmt(s *ast.ForStmt, label *lblock) {
- // ...init...
- // jump loop
- // loop:
- // if cond goto body else done
- // body:
- // ...body...
- // jump post
- // post: (target of continue)
- // ...post...
- // jump loop
- // done: (target of break)
- if s.Init != nil {
- b.stmt(s.Init)
- }
- body := b.newBlock("for.body")
- done := b.newBlock("for.done") // target of 'break'
- loop := body // target of back-edge
- if s.Cond != nil {
- loop = b.newBlock("for.loop")
- }
- cont := loop // target of 'continue'
- if s.Post != nil {
- cont = b.newBlock("for.post")
- }
- if label != nil {
- label._break = done
- label._continue = cont
- }
- b.jump(loop)
- b.current = loop
- if loop != body {
- b.add(s.Cond)
- b.ifelse(body, done)
- b.current = body
- }
- b.targets = &targets{
- tail: b.targets,
- _break: done,
- _continue: cont,
- }
- b.stmt(s.Body)
- b.targets = b.targets.tail
- b.jump(cont)
-
- if s.Post != nil {
- b.current = cont
- b.stmt(s.Post)
- b.jump(loop) // back-edge
- }
- b.current = done
-}
-
-func (b *builder) rangeStmt(s *ast.RangeStmt, label *lblock) {
- b.add(s.X)
-
- if s.Key != nil {
- b.add(s.Key)
- }
- if s.Value != nil {
- b.add(s.Value)
- }
-
- // ...
- // loop: (target of continue)
- // if ... goto body else done
- // body:
- // ...
- // jump loop
- // done: (target of break)
-
- loop := b.newBlock("range.loop")
- b.jump(loop)
- b.current = loop
-
- body := b.newBlock("range.body")
- done := b.newBlock("range.done")
- b.ifelse(body, done)
- b.current = body
-
- if label != nil {
- label._break = done
- label._continue = loop
- }
- b.targets = &targets{
- tail: b.targets,
- _break: done,
- _continue: loop,
- }
- b.stmt(s.Body)
- b.targets = b.targets.tail
- b.jump(loop) // back-edge
- b.current = done
-}
-
-// -------- helpers --------
-
-// Destinations associated with unlabeled for/switch/select stmts.
-// We push/pop one of these as we enter/leave each construct and for
-// each BranchStmt we scan for the innermost target of the right type.
-//
-type targets struct {
- tail *targets // rest of stack
- _break *Block
- _continue *Block
- _fallthrough *Block
-}
-
-// Destinations associated with a labeled block.
-// We populate these as labels are encountered in forward gotos or
-// labeled statements.
-//
-type lblock struct {
- _goto *Block
- _break *Block
- _continue *Block
-}
-
-// labeledBlock returns the branch target associated with the
-// specified label, creating it if needed.
-//
-func (b *builder) labeledBlock(label *ast.Ident) *lblock {
- lb := b.lblocks[label.Obj]
- if lb == nil {
- lb = &lblock{_goto: b.newBlock(label.Name)}
- if b.lblocks == nil {
- b.lblocks = make(map[*ast.Object]*lblock)
- }
- b.lblocks[label.Obj] = lb
- }
- return lb
-}
-
-// newBlock appends a new unconnected basic block to b.cfg's block
-// slice and returns it.
-// It does not automatically become the current block.
-// comment is an optional string for more readable debugging output.
-func (b *builder) newBlock(comment string) *Block {
- g := b.cfg
- block := &Block{
- index: int32(len(g.Blocks)),
- comment: comment,
- }
- block.Succs = block.succs2[:0]
- g.Blocks = append(g.Blocks, block)
- return block
-}
-
-func (b *builder) newUnreachableBlock(comment string) *Block {
- block := b.newBlock(comment)
- block.unreachable = true
- return block
-}
-
-func (b *builder) add(n ast.Node) {
- b.current.Nodes = append(b.current.Nodes, n)
-}
-
-// jump adds an edge from the current block to the target block,
-// and sets b.current to nil.
-func (b *builder) jump(target *Block) {
- b.current.Succs = append(b.current.Succs, target)
- b.current = nil
-}
-
-// ifelse emits edges from the current block to the t and f blocks,
-// and sets b.current to nil.
-func (b *builder) ifelse(t, f *Block) {
- b.current.Succs = append(b.current.Succs, t, f)
- b.current = nil
-}
diff --git a/libgo/go/cmd/vet/internal/cfg/cfg.go b/libgo/go/cmd/vet/internal/cfg/cfg.go
deleted file mode 100644
index e4d5bfe5d2d..00000000000
--- a/libgo/go/cmd/vet/internal/cfg/cfg.go
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This package constructs a simple control-flow graph (CFG) of the
-// statements and expressions within a single function.
-//
-// Use cfg.New to construct the CFG for a function body.
-//
-// The blocks of the CFG contain all the function's non-control
-// statements. The CFG does not contain control statements such as If,
-// Switch, Select, and Branch, but does contain their subexpressions.
-// For example, this source code:
-//
-// if x := f(); x != nil {
-// T()
-// } else {
-// F()
-// }
-//
-// produces this CFG:
-//
-// 1: x := f()
-// x != nil
-// succs: 2, 3
-// 2: T()
-// succs: 4
-// 3: F()
-// succs: 4
-// 4:
-//
-// The CFG does contain Return statements; even implicit returns are
-// materialized (at the position of the function's closing brace).
-//
-// The CFG does not record conditions associated with conditional branch
-// edges, nor the short-circuit semantics of the && and || operators,
-// nor abnormal control flow caused by panic. If you need this
-// information, use golang.org/x/tools/go/ssa instead.
-//
-package cfg
-
-// Although the vet tool has type information, it is often extremely
-// fragmentary, so for simplicity this package does not depend on
-// go/types. Consequently control-flow conditions are ignored even
-// when constant, and "mayReturn" information must be provided by the
-// client.
-import (
- "bytes"
- "fmt"
- "go/ast"
- "go/format"
- "go/token"
-)
-
-// A CFG represents the control-flow graph of a single function.
-//
-// The entry point is Blocks[0]; there may be multiple return blocks.
-type CFG struct {
- Blocks []*Block // block[0] is entry; order otherwise undefined
-}
-
-// A Block represents a basic block: a list of statements and
-// expressions that are always evaluated sequentially.
-//
-// A block may have 0-2 successors: zero for a return block or a block
-// that calls a function such as panic that never returns; one for a
-// normal (jump) block; and two for a conditional (if) block.
-type Block struct {
- Nodes []ast.Node // statements, expressions, and ValueSpecs
- Succs []*Block // successor nodes in the graph
-
- comment string // for debugging
- index int32 // index within CFG.Blocks
- unreachable bool // is block of stmts following return/panic/for{}
- succs2 [2]*Block // underlying array for Succs
-}
-
-// New returns a new control-flow graph for the specified function body,
-// which must be non-nil.
-//
-// The CFG builder calls mayReturn to determine whether a given function
-// call may return. For example, calls to panic, os.Exit, and log.Fatal
-// do not return, so the builder can remove infeasible graph edges
-// following such calls. The builder calls mayReturn only for a
-// CallExpr beneath an ExprStmt.
-func New(body *ast.BlockStmt, mayReturn func(*ast.CallExpr) bool) *CFG {
- b := builder{
- mayReturn: mayReturn,
- cfg: new(CFG),
- }
- b.current = b.newBlock("entry")
- b.stmt(body)
-
- // Does control fall off the end of the function's body?
- // Make implicit return explicit.
- if b.current != nil && !b.current.unreachable {
- b.add(&ast.ReturnStmt{
- Return: body.End() - 1,
- })
- }
-
- return b.cfg
-}
-
-func (b *Block) String() string {
- return fmt.Sprintf("block %d (%s)", b.index, b.comment)
-}
-
-// Return returns the return statement at the end of this block if present, nil otherwise.
-func (b *Block) Return() (ret *ast.ReturnStmt) {
- if len(b.Nodes) > 0 {
- ret, _ = b.Nodes[len(b.Nodes)-1].(*ast.ReturnStmt)
- }
- return
-}
-
-// Format formats the control-flow graph for ease of debugging.
-func (g *CFG) Format(fset *token.FileSet) string {
- var buf bytes.Buffer
- for _, b := range g.Blocks {
- fmt.Fprintf(&buf, ".%d: # %s\n", b.index, b.comment)
- for _, n := range b.Nodes {
- fmt.Fprintf(&buf, "\t%s\n", formatNode(fset, n))
- }
- if len(b.Succs) > 0 {
- fmt.Fprintf(&buf, "\tsuccs:")
- for _, succ := range b.Succs {
- fmt.Fprintf(&buf, " %d", succ.index)
- }
- buf.WriteByte('\n')
- }
- buf.WriteByte('\n')
- }
- return buf.String()
-}
-
-func formatNode(fset *token.FileSet, n ast.Node) string {
- var buf bytes.Buffer
- format.Node(&buf, fset, n)
- // Indent secondary lines by a tab.
- return string(bytes.Replace(buf.Bytes(), []byte("\n"), []byte("\n\t"), -1))
-}
diff --git a/libgo/go/cmd/vet/internal/cfg/cfg_test.go b/libgo/go/cmd/vet/internal/cfg/cfg_test.go
deleted file mode 100644
index 2400fed6f4b..00000000000
--- a/libgo/go/cmd/vet/internal/cfg/cfg_test.go
+++ /dev/null
@@ -1,190 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package cfg
-
-import (
- "bytes"
- "fmt"
- "go/ast"
- "go/parser"
- "go/token"
- "testing"
-)
-
-const src = `package main
-
-import "log"
-
-func f1() {
- live()
- return
- dead()
-}
-
-func f2() {
- for {
- live()
- }
- dead()
-}
-
-func f3() {
- if true { // even known values are ignored
- return
- }
- for true { // even known values are ignored
- live()
- }
- for {
- live()
- }
- dead()
-}
-
-func f4(x int) {
- switch x {
- case 1:
- live()
- fallthrough
- case 2:
- live()
- log.Fatal()
- default:
- panic("oops")
- }
- dead()
-}
-
-func f4(ch chan int) {
- select {
- case <-ch:
- live()
- return
- default:
- live()
- panic("oops")
- }
- dead()
-}
-
-func f5(unknown bool) {
- for {
- if unknown {
- break
- }
- continue
- dead()
- }
- live()
-}
-
-func f6(unknown bool) {
-outer:
- for {
- for {
- break outer
- dead()
- }
- dead()
- }
- live()
-}
-
-func f7() {
- for {
- break nosuchlabel
- dead()
- }
- dead()
-}
-
-func f8() {
- select{}
- dead()
-}
-
-func f9(ch chan int) {
- select {
- case <-ch:
- return
- }
- dead()
-}
-
-func f10(ch chan int) {
- select {
- case <-ch:
- return
- dead()
- default:
- }
- live()
-}
-
-func f11() {
- goto; // mustn't crash
- dead()
-}
-
-`
-
-func TestDeadCode(t *testing.T) {
- // We'll use dead code detection to verify the CFG.
-
- fset := token.NewFileSet()
- f, err := parser.ParseFile(fset, "dummy.go", src, parser.Mode(0))
- if err != nil {
- t.Fatal(err)
- }
- for _, decl := range f.Decls {
- if decl, ok := decl.(*ast.FuncDecl); ok {
- g := New(decl.Body, mayReturn)
-
- // Mark blocks reachable from entry.
- live := make(map[*Block]bool)
- var visit func(*Block)
- visit = func(b *Block) {
- if !live[b] {
- live[b] = true
- for _, succ := range b.Succs {
- visit(succ)
- }
- }
- }
- visit(g.Blocks[0])
-
- // Print statements in unreachable blocks
- // (in order determined by builder).
- var buf bytes.Buffer
- for _, b := range g.Blocks {
- if !live[b] {
- for _, n := range b.Nodes {
- fmt.Fprintf(&buf, "\t%s\n", formatNode(fset, n))
- }
- }
- }
-
- // Check that the result contains "dead" at least once but not "live".
- if !bytes.Contains(buf.Bytes(), []byte("dead")) ||
- bytes.Contains(buf.Bytes(), []byte("live")) {
- t.Errorf("unexpected dead statements in function %s:\n%s",
- decl.Name.Name,
- &buf)
- t.Logf("control flow graph:\n%s", g.Format(fset))
- }
- }
- }
-}
-
-// A trivial mayReturn predicate that looks only at syntax, not types.
-func mayReturn(call *ast.CallExpr) bool {
- switch fun := call.Fun.(type) {
- case *ast.Ident:
- return fun.Name != "panic"
- case *ast.SelectorExpr:
- return fun.Sel.Name != "Fatal"
- }
- return true
-}
diff --git a/libgo/go/cmd/vet/internal/whitelist/whitelist.go b/libgo/go/cmd/vet/internal/whitelist/whitelist.go
deleted file mode 100644
index fdd65d37323..00000000000
--- a/libgo/go/cmd/vet/internal/whitelist/whitelist.go
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package whitelist defines exceptions for the vet tool.
-package whitelist
-
-// UnkeyedLiteral is a white list of types in the standard packages
-// that are used with unkeyed literals we deem to be acceptable.
-var UnkeyedLiteral = map[string]bool{
- // These image and image/color struct types are frozen. We will never add fields to them.
- "image/color.Alpha16": true,
- "image/color.Alpha": true,
- "image/color.CMYK": true,
- "image/color.Gray16": true,
- "image/color.Gray": true,
- "image/color.NRGBA64": true,
- "image/color.NRGBA": true,
- "image/color.NYCbCrA": true,
- "image/color.RGBA64": true,
- "image/color.RGBA": true,
- "image/color.YCbCr": true,
- "image.Point": true,
- "image.Rectangle": true,
- "image.Uniform": true,
-
- "unicode.Range16": true,
-}
diff --git a/libgo/go/cmd/vet/lostcancel.go b/libgo/go/cmd/vet/lostcancel.go
deleted file mode 100644
index ee0342035fe..00000000000
--- a/libgo/go/cmd/vet/lostcancel.go
+++ /dev/null
@@ -1,322 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "cmd/vet/internal/cfg"
- "fmt"
- "go/ast"
- "go/types"
- "strconv"
-)
-
-func init() {
- register("lostcancel",
- "check for failure to call cancelation function returned by context.WithCancel",
- checkLostCancel,
- funcDecl, funcLit)
-}
-
-const debugLostCancel = false
-
-var contextPackage = "context"
-
-// checkLostCancel reports a failure to the call the cancel function
-// returned by context.WithCancel, either because the variable was
-// assigned to the blank identifier, or because there exists a
-// control-flow path from the call to a return statement and that path
-// does not "use" the cancel function. Any reference to the variable
-// counts as a use, even within a nested function literal.
-//
-// checkLostCancel analyzes a single named or literal function.
-func checkLostCancel(f *File, node ast.Node) {
- // Fast path: bypass check if file doesn't use context.WithCancel.
- if !hasImport(f.file, contextPackage) {
- return
- }
-
- // Maps each cancel variable to its defining ValueSpec/AssignStmt.
- cancelvars := make(map[*types.Var]ast.Node)
-
- // Find the set of cancel vars to analyze.
- stack := make([]ast.Node, 0, 32)
- ast.Inspect(node, func(n ast.Node) bool {
- switch n.(type) {
- case *ast.FuncLit:
- if len(stack) > 0 {
- return false // don't stray into nested functions
- }
- case nil:
- stack = stack[:len(stack)-1] // pop
- return true
- }
- stack = append(stack, n) // push
-
- // Look for [{AssignStmt,ValueSpec} CallExpr SelectorExpr]:
- //
- // ctx, cancel := context.WithCancel(...)
- // ctx, cancel = context.WithCancel(...)
- // var ctx, cancel = context.WithCancel(...)
- //
- if isContextWithCancel(f, n) && isCall(stack[len(stack)-2]) {
- var id *ast.Ident // id of cancel var
- stmt := stack[len(stack)-3]
- switch stmt := stmt.(type) {
- case *ast.ValueSpec:
- if len(stmt.Names) > 1 {
- id = stmt.Names[1]
- }
- case *ast.AssignStmt:
- if len(stmt.Lhs) > 1 {
- id, _ = stmt.Lhs[1].(*ast.Ident)
- }
- }
- if id != nil {
- if id.Name == "_" {
- f.Badf(id.Pos(), "the cancel function returned by context.%s should be called, not discarded, to avoid a context leak",
- n.(*ast.SelectorExpr).Sel.Name)
- } else if v, ok := f.pkg.uses[id].(*types.Var); ok {
- cancelvars[v] = stmt
- } else if v, ok := f.pkg.defs[id].(*types.Var); ok {
- cancelvars[v] = stmt
- }
- }
- }
-
- return true
- })
-
- if len(cancelvars) == 0 {
- return // no need to build CFG
- }
-
- // Tell the CFG builder which functions never return.
- info := &types.Info{Uses: f.pkg.uses, Selections: f.pkg.selectors}
- mayReturn := func(call *ast.CallExpr) bool {
- name := callName(info, call)
- return !noReturnFuncs[name]
- }
-
- // Build the CFG.
- var g *cfg.CFG
- var sig *types.Signature
- switch node := node.(type) {
- case *ast.FuncDecl:
- obj := f.pkg.defs[node.Name]
- if obj == nil {
- return // type error (e.g. duplicate function declaration)
- }
- sig, _ = obj.Type().(*types.Signature)
- g = cfg.New(node.Body, mayReturn)
- case *ast.FuncLit:
- sig, _ = f.pkg.types[node.Type].Type.(*types.Signature)
- g = cfg.New(node.Body, mayReturn)
- }
-
- // Print CFG.
- if debugLostCancel {
- fmt.Println(g.Format(f.fset))
- }
-
- // Examine the CFG for each variable in turn.
- // (It would be more efficient to analyze all cancelvars in a
- // single pass over the AST, but seldom is there more than one.)
- for v, stmt := range cancelvars {
- if ret := lostCancelPath(f, g, v, stmt, sig); ret != nil {
- lineno := f.fset.Position(stmt.Pos()).Line
- f.Badf(stmt.Pos(), "the %s function is not used on all paths (possible context leak)", v.Name())
- f.Badf(ret.Pos(), "this return statement may be reached without using the %s var defined on line %d", v.Name(), lineno)
- }
- }
-}
-
-func isCall(n ast.Node) bool { _, ok := n.(*ast.CallExpr); return ok }
-
-func hasImport(f *ast.File, path string) bool {
- for _, imp := range f.Imports {
- v, _ := strconv.Unquote(imp.Path.Value)
- if v == path {
- return true
- }
- }
- return false
-}
-
-// isContextWithCancel reports whether n is one of the qualified identifiers
-// context.With{Cancel,Timeout,Deadline}.
-func isContextWithCancel(f *File, n ast.Node) bool {
- if sel, ok := n.(*ast.SelectorExpr); ok {
- switch sel.Sel.Name {
- case "WithCancel", "WithTimeout", "WithDeadline":
- if x, ok := sel.X.(*ast.Ident); ok {
- if pkgname, ok := f.pkg.uses[x].(*types.PkgName); ok {
- return pkgname.Imported().Path() == contextPackage
- }
- // Import failed, so we can't check package path.
- // Just check the local package name (heuristic).
- return x.Name == "context"
- }
- }
- }
- return false
-}
-
-// lostCancelPath finds a path through the CFG, from stmt (which defines
-// the 'cancel' variable v) to a return statement, that doesn't "use" v.
-// If it finds one, it returns the return statement (which may be synthetic).
-// sig is the function's type, if known.
-func lostCancelPath(f *File, g *cfg.CFG, v *types.Var, stmt ast.Node, sig *types.Signature) *ast.ReturnStmt {
- vIsNamedResult := sig != nil && tupleContains(sig.Results(), v)
-
- // uses reports whether stmts contain a "use" of variable v.
- uses := func(f *File, v *types.Var, stmts []ast.Node) bool {
- found := false
- for _, stmt := range stmts {
- ast.Inspect(stmt, func(n ast.Node) bool {
- switch n := n.(type) {
- case *ast.Ident:
- if f.pkg.uses[n] == v {
- found = true
- }
- case *ast.ReturnStmt:
- // A naked return statement counts as a use
- // of the named result variables.
- if n.Results == nil && vIsNamedResult {
- found = true
- }
- }
- return !found
- })
- }
- return found
- }
-
- // blockUses computes "uses" for each block, caching the result.
- memo := make(map[*cfg.Block]bool)
- blockUses := func(f *File, v *types.Var, b *cfg.Block) bool {
- res, ok := memo[b]
- if !ok {
- res = uses(f, v, b.Nodes)
- memo[b] = res
- }
- return res
- }
-
- // Find the var's defining block in the CFG,
- // plus the rest of the statements of that block.
- var defblock *cfg.Block
- var rest []ast.Node
-outer:
- for _, b := range g.Blocks {
- for i, n := range b.Nodes {
- if n == stmt {
- defblock = b
- rest = b.Nodes[i+1:]
- break outer
- }
- }
- }
- if defblock == nil {
- panic("internal error: can't find defining block for cancel var")
- }
-
- // Is v "used" in the remainder of its defining block?
- if uses(f, v, rest) {
- return nil
- }
-
- // Does the defining block return without using v?
- if ret := defblock.Return(); ret != nil {
- return ret
- }
-
- // Search the CFG depth-first for a path, from defblock to a
- // return block, in which v is never "used".
- seen := make(map[*cfg.Block]bool)
- var search func(blocks []*cfg.Block) *ast.ReturnStmt
- search = func(blocks []*cfg.Block) *ast.ReturnStmt {
- for _, b := range blocks {
- if !seen[b] {
- seen[b] = true
-
- // Prune the search if the block uses v.
- if blockUses(f, v, b) {
- continue
- }
-
- // Found path to return statement?
- if ret := b.Return(); ret != nil {
- if debugLostCancel {
- fmt.Printf("found path to return in block %s\n", b)
- }
- return ret // found
- }
-
- // Recur
- if ret := search(b.Succs); ret != nil {
- if debugLostCancel {
- fmt.Printf(" from block %s\n", b)
- }
- return ret
- }
- }
- }
- return nil
- }
- return search(defblock.Succs)
-}
-
-func tupleContains(tuple *types.Tuple, v *types.Var) bool {
- for i := 0; i < tuple.Len(); i++ {
- if tuple.At(i) == v {
- return true
- }
- }
- return false
-}
-
-var noReturnFuncs = map[string]bool{
- "(*testing.common).FailNow": true,
- "(*testing.common).Fatal": true,
- "(*testing.common).Fatalf": true,
- "(*testing.common).Skip": true,
- "(*testing.common).SkipNow": true,
- "(*testing.common).Skipf": true,
- "log.Fatal": true,
- "log.Fatalf": true,
- "log.Fatalln": true,
- "os.Exit": true,
- "panic": true,
- "runtime.Goexit": true,
-}
-
-// callName returns the canonical name of the builtin, method, or
-// function called by call, if known.
-func callName(info *types.Info, call *ast.CallExpr) string {
- switch fun := call.Fun.(type) {
- case *ast.Ident:
- // builtin, e.g. "panic"
- if obj, ok := info.Uses[fun].(*types.Builtin); ok {
- return obj.Name()
- }
- case *ast.SelectorExpr:
- if sel, ok := info.Selections[fun]; ok && sel.Kind() == types.MethodVal {
- // method call, e.g. "(*testing.common).Fatal"
- meth := sel.Obj()
- return fmt.Sprintf("(%s).%s",
- meth.Type().(*types.Signature).Recv().Type(),
- meth.Name())
- }
- if obj, ok := info.Uses[fun.Sel]; ok {
- // qualified identifier, e.g. "os.Exit"
- return fmt.Sprintf("%s.%s",
- obj.Pkg().Path(),
- obj.Name())
- }
- }
-
- // function with no name, or defined in missing imported package
- return ""
-}
diff --git a/libgo/go/cmd/vet/main.go b/libgo/go/cmd/vet/main.go
index c50d4885a07..4ec174b3cd1 100644
--- a/libgo/go/cmd/vet/main.go
+++ b/libgo/go/cmd/vet/main.go
@@ -1,750 +1,53 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Vet is a simple checker for static errors in Go source code.
-// See doc.go for more information.
-
package main
import (
- "bytes"
- "encoding/gob"
- "encoding/json"
- "flag"
- "fmt"
- "go/ast"
- "go/build"
- "go/importer"
- "go/parser"
- "go/printer"
- "go/token"
- "go/types"
- "io"
- "io/ioutil"
- "os"
- "path/filepath"
- "sort"
- "strconv"
- "strings"
-
- "cmd/internal/objabi"
-)
-
-// Important! If you add flags here, make sure to update cmd/go/internal/vet/vetflag.go.
-
-var (
- verbose = flag.Bool("v", false, "verbose")
- source = flag.Bool("source", false, "import from source instead of compiled object files")
- tags = flag.String("tags", "", "space-separated list of build tags to apply when parsing")
- tagList = []string{} // exploded version of tags flag; set in main
-
- vcfg vetConfig
- mustTypecheck bool
-)
-
-var exitCode = 0
-
-// "-all" flag enables all non-experimental checks
-var all = triStateFlag("all", unset, "enable all non-experimental checks")
-
-// Flags to control which individual checks to perform.
-var report = map[string]*triState{
- // Only unusual checks are written here.
- // Most checks that operate during the AST walk are added by register.
- "asmdecl": triStateFlag("asmdecl", unset, "check assembly against Go declarations"),
- "buildtags": triStateFlag("buildtags", unset, "check that +build tags are valid"),
-}
-
-// experimental records the flags enabling experimental features. These must be
-// requested explicitly; they are not enabled by -all.
-var experimental = map[string]bool{}
-
-// setTrueCount record how many flags are explicitly set to true.
-var setTrueCount int
-
-// dirsRun and filesRun indicate whether the vet is applied to directory or
-// file targets. The distinction affects which checks are run.
-var dirsRun, filesRun bool
-
-// includesNonTest indicates whether the vet is applied to non-test targets.
-// Certain checks are relevant only if they touch both test and non-test files.
-var includesNonTest bool
-
-// A triState is a boolean that knows whether it has been set to either true or false.
-// It is used to identify if a flag appears; the standard boolean flag cannot
-// distinguish missing from unset. It also satisfies flag.Value.
-type triState int
-
-const (
- unset triState = iota
- setTrue
- setFalse
-)
-
-func triStateFlag(name string, value triState, usage string) *triState {
- flag.Var(&value, name, usage)
- return &value
-}
-
-// triState implements flag.Value, flag.Getter, and flag.boolFlag.
-// They work like boolean flags: we can say vet -printf as well as vet -printf=true
-func (ts *triState) Get() interface{} {
- return *ts == setTrue
-}
-
-func (ts triState) isTrue() bool {
- return ts == setTrue
-}
-
-func (ts *triState) Set(value string) error {
- b, err := strconv.ParseBool(value)
- if err != nil {
- return err
- }
- if b {
- *ts = setTrue
- setTrueCount++
- } else {
- *ts = setFalse
- }
- return nil
-}
-
-func (ts *triState) String() string {
- switch *ts {
- case unset:
- return "true" // An unset flag will be set by -all, so defaults to true.
- case setTrue:
- return "true"
- case setFalse:
- return "false"
- }
- panic("not reached")
-}
-
-func (ts triState) IsBoolFlag() bool {
- return true
-}
-
-// vet tells whether to report errors for the named check, a flag name.
-func vet(name string) bool {
- return report[name].isTrue()
-}
-
-// setExit sets the value for os.Exit when it is called, later. It
-// remembers the highest value.
-func setExit(err int) {
- if err > exitCode {
- exitCode = err
- }
-}
-
-var (
- // Each of these vars has a corresponding case in (*File).Visit.
- assignStmt *ast.AssignStmt
- binaryExpr *ast.BinaryExpr
- callExpr *ast.CallExpr
- compositeLit *ast.CompositeLit
- exprStmt *ast.ExprStmt
- forStmt *ast.ForStmt
- funcDecl *ast.FuncDecl
- funcLit *ast.FuncLit
- genDecl *ast.GenDecl
- interfaceType *ast.InterfaceType
- rangeStmt *ast.RangeStmt
- returnStmt *ast.ReturnStmt
- structType *ast.StructType
-
- // checkers is a two-level map.
- // The outer level is keyed by a nil pointer, one of the AST vars above.
- // The inner level is keyed by checker name.
- checkers = make(map[ast.Node]map[string]func(*File, ast.Node))
- pkgCheckers = make(map[string]func(*Package))
- exporters = make(map[string]func() interface{})
+ "golang.org/x/tools/go/analysis/unitchecker"
+
+ "golang.org/x/tools/go/analysis/passes/asmdecl"
+ "golang.org/x/tools/go/analysis/passes/assign"
+ "golang.org/x/tools/go/analysis/passes/atomic"
+ "golang.org/x/tools/go/analysis/passes/bools"
+ "golang.org/x/tools/go/analysis/passes/buildtag"
+ "golang.org/x/tools/go/analysis/passes/cgocall"
+ "golang.org/x/tools/go/analysis/passes/composite"
+ "golang.org/x/tools/go/analysis/passes/copylock"
+ "golang.org/x/tools/go/analysis/passes/httpresponse"
+ "golang.org/x/tools/go/analysis/passes/loopclosure"
+ "golang.org/x/tools/go/analysis/passes/lostcancel"
+ "golang.org/x/tools/go/analysis/passes/nilfunc"
+ "golang.org/x/tools/go/analysis/passes/printf"
+ "golang.org/x/tools/go/analysis/passes/shift"
+ "golang.org/x/tools/go/analysis/passes/stdmethods"
+ "golang.org/x/tools/go/analysis/passes/structtag"
+ "golang.org/x/tools/go/analysis/passes/tests"
+ "golang.org/x/tools/go/analysis/passes/unmarshal"
+ "golang.org/x/tools/go/analysis/passes/unreachable"
+ "golang.org/x/tools/go/analysis/passes/unsafeptr"
+ "golang.org/x/tools/go/analysis/passes/unusedresult"
)
-// The exporters data as written to the vetx output file.
-type vetxExport struct {
- Name string
- Data interface{}
-}
-
-// Vet can provide its own "export information"
-// about package A to future invocations of vet
-// on packages importing A. If B imports A,
-// then running "go vet B" actually invokes vet twice:
-// first, it runs vet on A, in "vetx-only" mode, which
-// skips most checks and only computes export data
-// describing A. Then it runs vet on B, making A's vetx
-// data available for consultation. The vet of B
-// computes vetx data for B in addition to its
-// usual vet checks.
-
-// register registers the named check function,
-// to be called with AST nodes of the given types.
-// The registered functions are not called in vetx-only mode.
-func register(name, usage string, fn func(*File, ast.Node), types ...ast.Node) {
- report[name] = triStateFlag(name, unset, usage)
- for _, typ := range types {
- m := checkers[typ]
- if m == nil {
- m = make(map[string]func(*File, ast.Node))
- checkers[typ] = m
- }
- m[name] = fn
- }
-}
-
-// registerPkgCheck registers a package-level checking function,
-// to be invoked with the whole package being vetted
-// before any of the per-node handlers.
-// The registered function fn is called even in vetx-only mode
-// (see comment above), so fn must take care not to report
-// errors when vcfg.VetxOnly is true.
-func registerPkgCheck(name string, fn func(*Package)) {
- pkgCheckers[name] = fn
-}
-
-// registerExport registers a function to return vetx export data
-// that should be saved and provided to future invocations of vet
-// when checking packages importing this one.
-// The value returned by fn should be nil or else valid to encode using gob.
-// Typically a registerExport call is paired with a call to gob.Register.
-func registerExport(name string, fn func() interface{}) {
- exporters[name] = fn
-}
-
-// Usage is a replacement usage function for the flags package.
-func Usage() {
- fmt.Fprintf(os.Stderr, "Usage of vet:\n")
- fmt.Fprintf(os.Stderr, "\tvet [flags] directory...\n")
- fmt.Fprintf(os.Stderr, "\tvet [flags] files... # Must be a single package\n")
- fmt.Fprintf(os.Stderr, "By default, -all is set and all non-experimental checks are run.\n")
- fmt.Fprintf(os.Stderr, "For more information run\n")
- fmt.Fprintf(os.Stderr, "\tgo doc cmd/vet\n\n")
- fmt.Fprintf(os.Stderr, "Flags:\n")
- flag.PrintDefaults()
- os.Exit(2)
-}
-
-// File is a wrapper for the state of a file used in the parser.
-// The parse tree walkers are all methods of this type.
-type File struct {
- pkg *Package
- fset *token.FileSet
- name string
- content []byte
- file *ast.File
- b bytes.Buffer // for use by methods
-
- // Parsed package "foo" when checking package "foo_test"
- basePkg *Package
-
- // The keys are the objects that are receivers of a "String()
- // string" method. The value reports whether the method has a
- // pointer receiver.
- // This is used by the recursiveStringer method in print.go.
- stringerPtrs map[*ast.Object]bool
-
- // Registered checkers to run.
- checkers map[ast.Node][]func(*File, ast.Node)
-
- // Unreachable nodes; can be ignored in shift check.
- dead map[ast.Node]bool
-}
-
func main() {
- objabi.AddVersionFlag()
- flag.Usage = Usage
- flag.Parse()
-
- // If any flag is set, we run only those checks requested.
- // If all flag is set true or if no flags are set true, set all the non-experimental ones
- // not explicitly set (in effect, set the "-all" flag).
- if setTrueCount == 0 || *all == setTrue {
- for name, setting := range report {
- if *setting == unset && !experimental[name] {
- *setting = setTrue
- }
- }
- }
-
- // Accept space-separated tags because that matches
- // the go command's other subcommands.
- // Accept commas because go tool vet traditionally has.
- tagList = strings.Fields(strings.Replace(*tags, ",", " ", -1))
-
- initPrintFlags()
- initUnusedFlags()
-
- if flag.NArg() == 0 {
- Usage()
- }
-
- // Special case for "go vet" passing an explicit configuration:
- // single argument ending in vet.cfg.
- // Once we have a more general mechanism for obtaining this
- // information from build tools like the go command,
- // vet should be changed to use it. This vet.cfg hack is an
- // experiment to learn about what form that information should take.
- if flag.NArg() == 1 && strings.HasSuffix(flag.Arg(0), "vet.cfg") {
- doPackageCfg(flag.Arg(0))
- os.Exit(exitCode)
- }
-
- for _, name := range flag.Args() {
- // Is it a directory?
- fi, err := os.Stat(name)
- if err != nil {
- warnf("error walking tree: %s", err)
- continue
- }
- if fi.IsDir() {
- dirsRun = true
- } else {
- filesRun = true
- if !strings.HasSuffix(name, "_test.go") {
- includesNonTest = true
- }
- }
- }
- if dirsRun && filesRun {
- Usage()
- }
- if dirsRun {
- for _, name := range flag.Args() {
- walkDir(name)
- }
- os.Exit(exitCode)
- }
- if doPackage(flag.Args(), nil) == nil {
- warnf("no files checked")
- }
- os.Exit(exitCode)
-}
-
-// prefixDirectory places the directory name on the beginning of each name in the list.
-func prefixDirectory(directory string, names []string) {
- if directory != "." {
- for i, name := range names {
- names[i] = filepath.Join(directory, name)
- }
- }
-}
-
-// vetConfig is the JSON config struct prepared by the Go command.
-type vetConfig struct {
- Compiler string
- Dir string
- ImportPath string
- GoFiles []string
- ImportMap map[string]string
- PackageFile map[string]string
- Standard map[string]bool
- PackageVetx map[string]string // map from import path to vetx data file
- VetxOnly bool // only compute vetx output; don't run ordinary checks
- VetxOutput string // file where vetx output should be written
-
- SucceedOnTypecheckFailure bool
-
- imp types.Importer
-}
-
-func (v *vetConfig) Import(path string) (*types.Package, error) {
- if v.imp == nil {
- v.imp = importer.For(v.Compiler, v.openPackageFile)
- }
- if path == "unsafe" {
- return v.imp.Import("unsafe")
- }
- p := v.ImportMap[path]
- if p == "" {
- return nil, fmt.Errorf("unknown import path %q", path)
- }
- if v.PackageFile[p] == "" {
- if v.Compiler == "gccgo" && v.Standard[path] {
- // gccgo doesn't have sources for standard library packages,
- // but the importer will do the right thing.
- return v.imp.Import(path)
- }
- return nil, fmt.Errorf("unknown package file for import %q", path)
- }
- return v.imp.Import(p)
-}
-
-func (v *vetConfig) openPackageFile(path string) (io.ReadCloser, error) {
- file := v.PackageFile[path]
- if file == "" {
- if v.Compiler == "gccgo" && v.Standard[path] {
- // The importer knows how to handle this.
- return nil, nil
- }
- // Note that path here has been translated via v.ImportMap,
- // unlike in the error in Import above. We prefer the error in
- // Import, but it's worth diagnosing this one too, just in case.
- return nil, fmt.Errorf("unknown package file for %q", path)
- }
- f, err := os.Open(file)
- if err != nil {
- return nil, err
- }
- return f, nil
-}
-
-// doPackageCfg analyzes a single package described in a config file.
-func doPackageCfg(cfgFile string) {
- js, err := ioutil.ReadFile(cfgFile)
- if err != nil {
- errorf("%v", err)
- }
- if err := json.Unmarshal(js, &vcfg); err != nil {
- errorf("parsing vet config %s: %v", cfgFile, err)
- }
- stdImporter = &vcfg
- inittypes()
- mustTypecheck = true
- doPackage(vcfg.GoFiles, nil)
- if vcfg.VetxOutput != "" {
- out := make([]vetxExport, 0, len(exporters))
- for name, fn := range exporters {
- out = append(out, vetxExport{
- Name: name,
- Data: fn(),
- })
- }
- // Sort the data so that it is consistent across builds.
- sort.Slice(out, func(i, j int) bool {
- return out[i].Name < out[j].Name
- })
- var buf bytes.Buffer
- if err := gob.NewEncoder(&buf).Encode(out); err != nil {
- errorf("encoding vet output: %v", err)
- return
- }
- if err := ioutil.WriteFile(vcfg.VetxOutput, buf.Bytes(), 0666); err != nil {
- errorf("saving vet output: %v", err)
- return
- }
- }
-}
-
-// doPackageDir analyzes the single package found in the directory, if there is one,
-// plus a test package, if there is one.
-func doPackageDir(directory string) {
- context := build.Default
- if len(context.BuildTags) != 0 {
- warnf("build tags %s previously set", context.BuildTags)
- }
- context.BuildTags = append(tagList, context.BuildTags...)
-
- pkg, err := context.ImportDir(directory, 0)
- if err != nil {
- // If it's just that there are no go source files, that's fine.
- if _, nogo := err.(*build.NoGoError); nogo {
- return
- }
- // Non-fatal: we are doing a recursive walk and there may be other directories.
- warnf("cannot process directory %s: %s", directory, err)
- return
- }
- var names []string
- names = append(names, pkg.GoFiles...)
- names = append(names, pkg.CgoFiles...)
- names = append(names, pkg.TestGoFiles...) // These are also in the "foo" package.
- names = append(names, pkg.SFiles...)
- prefixDirectory(directory, names)
- basePkg := doPackage(names, nil)
- // Is there also a "foo_test" package? If so, do that one as well.
- if len(pkg.XTestGoFiles) > 0 {
- names = pkg.XTestGoFiles
- prefixDirectory(directory, names)
- doPackage(names, basePkg)
- }
-}
-
-type Package struct {
- path string
- defs map[*ast.Ident]types.Object
- uses map[*ast.Ident]types.Object
- selectors map[*ast.SelectorExpr]*types.Selection
- types map[ast.Expr]types.TypeAndValue
- spans map[types.Object]Span
- files []*File
- typesPkg *types.Package
-}
-
-// doPackage analyzes the single package constructed from the named files.
-// It returns the parsed Package or nil if none of the files have been checked.
-func doPackage(names []string, basePkg *Package) *Package {
- var files []*File
- var astFiles []*ast.File
- fs := token.NewFileSet()
- for _, name := range names {
- data, err := ioutil.ReadFile(name)
- if err != nil {
- // Warn but continue to next package.
- warnf("%s: %s", name, err)
- return nil
- }
- var parsedFile *ast.File
- if strings.HasSuffix(name, ".go") {
- parsedFile, err = parser.ParseFile(fs, name, data, parser.ParseComments)
- if err != nil {
- warnf("%s: %s", name, err)
- return nil
- }
- astFiles = append(astFiles, parsedFile)
- }
- file := &File{
- fset: fs,
- content: data,
- name: name,
- file: parsedFile,
- dead: make(map[ast.Node]bool),
- }
- files = append(files, file)
- }
- if len(astFiles) == 0 {
- return nil
- }
- pkg := new(Package)
- pkg.path = astFiles[0].Name.Name
- pkg.files = files
- // Type check the package.
- errs := pkg.check(fs, astFiles)
- if errs != nil {
- if vcfg.SucceedOnTypecheckFailure {
- os.Exit(0)
- }
- if *verbose || mustTypecheck {
- for _, err := range errs {
- fmt.Fprintf(os.Stderr, "%v\n", err)
- }
- if mustTypecheck {
- // This message could be silenced, and we could just exit,
- // but it might be helpful at least at first to make clear that the
- // above errors are coming from vet and not the compiler
- // (they often look like compiler errors, such as "declared but not used").
- errorf("typecheck failures")
- }
- }
- }
-
- // Check.
- for _, file := range files {
- file.pkg = pkg
- file.basePkg = basePkg
- }
- for name, fn := range pkgCheckers {
- if vet(name) {
- fn(pkg)
- }
- }
- if vcfg.VetxOnly {
- return pkg
- }
-
- chk := make(map[ast.Node][]func(*File, ast.Node))
- for typ, set := range checkers {
- for name, fn := range set {
- if vet(name) {
- chk[typ] = append(chk[typ], fn)
- }
- }
- }
- for _, file := range files {
- checkBuildTag(file)
- file.checkers = chk
- if file.file != nil {
- file.walkFile(file.name, file.file)
- }
- }
- return pkg
-}
-
-func visit(path string, f os.FileInfo, err error) error {
- if err != nil {
- warnf("walk error: %s", err)
- return err
- }
- // One package per directory. Ignore the files themselves.
- if !f.IsDir() {
- return nil
- }
- doPackageDir(path)
- return nil
-}
-
-func (pkg *Package) hasFileWithSuffix(suffix string) bool {
- for _, f := range pkg.files {
- if strings.HasSuffix(f.name, suffix) {
- return true
- }
- }
- return false
-}
-
-// walkDir recursively walks the tree looking for Go packages.
-func walkDir(root string) {
- filepath.Walk(root, visit)
-}
-
-// errorf formats the error to standard error, adding program
-// identification and a newline, and exits.
-func errorf(format string, args ...interface{}) {
- fmt.Fprintf(os.Stderr, "vet: "+format+"\n", args...)
- os.Exit(2)
-}
-
-// warnf formats the error to standard error, adding program
-// identification and a newline, but does not exit.
-func warnf(format string, args ...interface{}) {
- fmt.Fprintf(os.Stderr, "vet: "+format+"\n", args...)
- setExit(1)
-}
-
-// Println is fmt.Println guarded by -v.
-func Println(args ...interface{}) {
- if !*verbose {
- return
- }
- fmt.Println(args...)
-}
-
-// Printf is fmt.Printf guarded by -v.
-func Printf(format string, args ...interface{}) {
- if !*verbose {
- return
- }
- fmt.Printf(format+"\n", args...)
-}
-
-// Bad reports an error and sets the exit code..
-func (f *File) Bad(pos token.Pos, args ...interface{}) {
- f.Warn(pos, args...)
- setExit(1)
-}
-
-// Badf reports a formatted error and sets the exit code.
-func (f *File) Badf(pos token.Pos, format string, args ...interface{}) {
- f.Warnf(pos, format, args...)
- setExit(1)
-}
-
-// loc returns a formatted representation of the position.
-func (f *File) loc(pos token.Pos) string {
- if pos == token.NoPos {
- return ""
- }
- // Do not print columns. Because the pos often points to the start of an
- // expression instead of the inner part with the actual error, the
- // precision can mislead.
- posn := f.fset.Position(pos)
- return fmt.Sprintf("%s:%d", posn.Filename, posn.Line)
-}
-
-// locPrefix returns a formatted representation of the position for use as a line prefix.
-func (f *File) locPrefix(pos token.Pos) string {
- if pos == token.NoPos {
- return ""
- }
- return fmt.Sprintf("%s: ", f.loc(pos))
-}
-
-// Warn reports an error but does not set the exit code.
-func (f *File) Warn(pos token.Pos, args ...interface{}) {
- fmt.Fprintf(os.Stderr, "%s%s", f.locPrefix(pos), fmt.Sprintln(args...))
-}
-
-// Warnf reports a formatted error but does not set the exit code.
-func (f *File) Warnf(pos token.Pos, format string, args ...interface{}) {
- fmt.Fprintf(os.Stderr, "%s%s\n", f.locPrefix(pos), fmt.Sprintf(format, args...))
-}
-
-// walkFile walks the file's tree.
-func (f *File) walkFile(name string, file *ast.File) {
- Println("Checking file", name)
- ast.Walk(f, file)
-}
-
-// Visit implements the ast.Visitor interface.
-func (f *File) Visit(node ast.Node) ast.Visitor {
- f.updateDead(node)
- var key ast.Node
- switch node.(type) {
- case *ast.AssignStmt:
- key = assignStmt
- case *ast.BinaryExpr:
- key = binaryExpr
- case *ast.CallExpr:
- key = callExpr
- case *ast.CompositeLit:
- key = compositeLit
- case *ast.ExprStmt:
- key = exprStmt
- case *ast.ForStmt:
- key = forStmt
- case *ast.FuncDecl:
- key = funcDecl
- case *ast.FuncLit:
- key = funcLit
- case *ast.GenDecl:
- key = genDecl
- case *ast.InterfaceType:
- key = interfaceType
- case *ast.RangeStmt:
- key = rangeStmt
- case *ast.ReturnStmt:
- key = returnStmt
- case *ast.StructType:
- key = structType
- }
- for _, fn := range f.checkers[key] {
- fn(f, node)
- }
- return f
-}
-
-// gofmt returns a string representation of the expression.
-func (f *File) gofmt(x ast.Expr) string {
- f.b.Reset()
- printer.Fprint(&f.b, f.fset, x)
- return f.b.String()
-}
-
-// imported[path][key] is previously written export data.
-var imported = make(map[string]map[string]interface{})
-
-// readVetx reads export data written by a previous
-// invocation of vet on an imported package (path).
-// The key is the name passed to registerExport
-// when the data was originally generated.
-// readVetx returns nil if the data is unavailable.
-func readVetx(path, key string) interface{} {
- if path == "unsafe" || vcfg.ImportPath == "" {
- return nil
- }
- m := imported[path]
- if m == nil {
- file := vcfg.PackageVetx[path]
- if file == "" {
- return nil
- }
- data, err := ioutil.ReadFile(file)
- if err != nil {
- return nil
- }
- var out []vetxExport
- err = gob.NewDecoder(bytes.NewReader(data)).Decode(&out)
- if err != nil {
- return nil
- }
- m = make(map[string]interface{})
- for _, x := range out {
- m[x.Name] = x.Data
- }
- imported[path] = m
- }
- return m[key]
+ unitchecker.Main(
+ asmdecl.Analyzer,
+ assign.Analyzer,
+ atomic.Analyzer,
+ bools.Analyzer,
+ buildtag.Analyzer,
+ cgocall.Analyzer,
+ composite.Analyzer,
+ copylock.Analyzer,
+ httpresponse.Analyzer,
+ loopclosure.Analyzer,
+ lostcancel.Analyzer,
+ nilfunc.Analyzer,
+ printf.Analyzer,
+ shift.Analyzer,
+ stdmethods.Analyzer,
+ structtag.Analyzer,
+ tests.Analyzer,
+ unmarshal.Analyzer,
+ unreachable.Analyzer,
+ unsafeptr.Analyzer,
+ unusedresult.Analyzer,
+ )
}
diff --git a/libgo/go/cmd/vet/method.go b/libgo/go/cmd/vet/method.go
deleted file mode 100644
index 5783278d2c2..00000000000
--- a/libgo/go/cmd/vet/method.go
+++ /dev/null
@@ -1,179 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file contains the code to check canonical methods.
-
-package main
-
-import (
- "fmt"
- "go/ast"
- "go/printer"
- "strings"
-)
-
-func init() {
- register("methods",
- "check that canonically named methods are canonically defined",
- checkCanonicalMethod,
- funcDecl, interfaceType)
-}
-
-type MethodSig struct {
- args []string
- results []string
-}
-
-// canonicalMethods lists the input and output types for Go methods
-// that are checked using dynamic interface checks. Because the
-// checks are dynamic, such methods would not cause a compile error
-// if they have the wrong signature: instead the dynamic check would
-// fail, sometimes mysteriously. If a method is found with a name listed
-// here but not the input/output types listed here, vet complains.
-//
-// A few of the canonical methods have very common names.
-// For example, a type might implement a Scan method that
-// has nothing to do with fmt.Scanner, but we still want to check
-// the methods that are intended to implement fmt.Scanner.
-// To do that, the arguments that have a = prefix are treated as
-// signals that the canonical meaning is intended: if a Scan
-// method doesn't have a fmt.ScanState as its first argument,
-// we let it go. But if it does have a fmt.ScanState, then the
-// rest has to match.
-var canonicalMethods = map[string]MethodSig{
- // "Flush": {{}, {"error"}}, // http.Flusher and jpeg.writer conflict
- "Format": {[]string{"=fmt.State", "rune"}, []string{}}, // fmt.Formatter
- "GobDecode": {[]string{"[]byte"}, []string{"error"}}, // gob.GobDecoder
- "GobEncode": {[]string{}, []string{"[]byte", "error"}}, // gob.GobEncoder
- "MarshalJSON": {[]string{}, []string{"[]byte", "error"}}, // json.Marshaler
- "MarshalXML": {[]string{"*xml.Encoder", "xml.StartElement"}, []string{"error"}}, // xml.Marshaler
- "ReadByte": {[]string{}, []string{"byte", "error"}}, // io.ByteReader
- "ReadFrom": {[]string{"=io.Reader"}, []string{"int64", "error"}}, // io.ReaderFrom
- "ReadRune": {[]string{}, []string{"rune", "int", "error"}}, // io.RuneReader
- "Scan": {[]string{"=fmt.ScanState", "rune"}, []string{"error"}}, // fmt.Scanner
- "Seek": {[]string{"=int64", "int"}, []string{"int64", "error"}}, // io.Seeker
- "UnmarshalJSON": {[]string{"[]byte"}, []string{"error"}}, // json.Unmarshaler
- "UnmarshalXML": {[]string{"*xml.Decoder", "xml.StartElement"}, []string{"error"}}, // xml.Unmarshaler
- "UnreadByte": {[]string{}, []string{"error"}},
- "UnreadRune": {[]string{}, []string{"error"}},
- "WriteByte": {[]string{"byte"}, []string{"error"}}, // jpeg.writer (matching bufio.Writer)
- "WriteTo": {[]string{"=io.Writer"}, []string{"int64", "error"}}, // io.WriterTo
-}
-
-func checkCanonicalMethod(f *File, node ast.Node) {
- switch n := node.(type) {
- case *ast.FuncDecl:
- if n.Recv != nil {
- canonicalMethod(f, n.Name, n.Type)
- }
- case *ast.InterfaceType:
- for _, field := range n.Methods.List {
- for _, id := range field.Names {
- canonicalMethod(f, id, field.Type.(*ast.FuncType))
- }
- }
- }
-}
-
-func canonicalMethod(f *File, id *ast.Ident, t *ast.FuncType) {
- // Expected input/output.
- expect, ok := canonicalMethods[id.Name]
- if !ok {
- return
- }
-
- // Actual input/output
- args := typeFlatten(t.Params.List)
- var results []ast.Expr
- if t.Results != nil {
- results = typeFlatten(t.Results.List)
- }
-
- // Do the =s (if any) all match?
- if !f.matchParams(expect.args, args, "=") || !f.matchParams(expect.results, results, "=") {
- return
- }
-
- // Everything must match.
- if !f.matchParams(expect.args, args, "") || !f.matchParams(expect.results, results, "") {
- expectFmt := id.Name + "(" + argjoin(expect.args) + ")"
- if len(expect.results) == 1 {
- expectFmt += " " + argjoin(expect.results)
- } else if len(expect.results) > 1 {
- expectFmt += " (" + argjoin(expect.results) + ")"
- }
-
- f.b.Reset()
- if err := printer.Fprint(&f.b, f.fset, t); err != nil {
- fmt.Fprintf(&f.b, "<%s>", err)
- }
- actual := f.b.String()
- actual = strings.TrimPrefix(actual, "func")
- actual = id.Name + actual
-
- f.Badf(id.Pos(), "method %s should have signature %s", actual, expectFmt)
- }
-}
-
-func argjoin(x []string) string {
- y := make([]string, len(x))
- for i, s := range x {
- if s[0] == '=' {
- s = s[1:]
- }
- y[i] = s
- }
- return strings.Join(y, ", ")
-}
-
-// Turn parameter list into slice of types
-// (in the ast, types are Exprs).
-// Have to handle f(int, bool) and f(x, y, z int)
-// so not a simple 1-to-1 conversion.
-func typeFlatten(l []*ast.Field) []ast.Expr {
- var t []ast.Expr
- for _, f := range l {
- if len(f.Names) == 0 {
- t = append(t, f.Type)
- continue
- }
- for range f.Names {
- t = append(t, f.Type)
- }
- }
- return t
-}
-
-// Does each type in expect with the given prefix match the corresponding type in actual?
-func (f *File) matchParams(expect []string, actual []ast.Expr, prefix string) bool {
- for i, x := range expect {
- if !strings.HasPrefix(x, prefix) {
- continue
- }
- if i >= len(actual) {
- return false
- }
- if !f.matchParamType(x, actual[i]) {
- return false
- }
- }
- if prefix == "" && len(actual) > len(expect) {
- return false
- }
- return true
-}
-
-// Does this one type match?
-func (f *File) matchParamType(expect string, actual ast.Expr) bool {
- expect = strings.TrimPrefix(expect, "=")
- // Strip package name if we're in that package.
- if n := len(f.file.Name.Name); len(expect) > n && expect[:n] == f.file.Name.Name && expect[n] == '.' {
- expect = expect[n+1:]
- }
-
- // Overkill but easy.
- f.b.Reset()
- printer.Fprint(&f.b, f.fset, actual)
- return f.b.String() == expect
-}
diff --git a/libgo/go/cmd/vet/nilfunc.go b/libgo/go/cmd/vet/nilfunc.go
deleted file mode 100644
index bfe05e3353d..00000000000
--- a/libgo/go/cmd/vet/nilfunc.go
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-This file contains the code to check for useless function comparisons.
-A useless comparison is one like f == nil as opposed to f() == nil.
-*/
-
-package main
-
-import (
- "go/ast"
- "go/token"
- "go/types"
-)
-
-func init() {
- register("nilfunc",
- "check for comparisons between functions and nil",
- checkNilFuncComparison,
- binaryExpr)
-}
-
-func checkNilFuncComparison(f *File, node ast.Node) {
- e := node.(*ast.BinaryExpr)
-
- // Only want == or != comparisons.
- if e.Op != token.EQL && e.Op != token.NEQ {
- return
- }
-
- // Only want comparisons with a nil identifier on one side.
- var e2 ast.Expr
- switch {
- case f.isNil(e.X):
- e2 = e.Y
- case f.isNil(e.Y):
- e2 = e.X
- default:
- return
- }
-
- // Only want identifiers or selector expressions.
- var obj types.Object
- switch v := e2.(type) {
- case *ast.Ident:
- obj = f.pkg.uses[v]
- case *ast.SelectorExpr:
- obj = f.pkg.uses[v.Sel]
- default:
- return
- }
-
- // Only want functions.
- if _, ok := obj.(*types.Func); !ok {
- return
- }
-
- f.Badf(e.Pos(), "comparison of function %v %v nil is always %v", obj.Name(), e.Op, e.Op == token.NEQ)
-}
-
-// isNil reports whether the provided expression is the built-in nil
-// identifier.
-func (f *File) isNil(e ast.Expr) bool {
- return f.pkg.types[e].Type == types.Typ[types.UntypedNil]
-}
diff --git a/libgo/go/cmd/vet/print.go b/libgo/go/cmd/vet/print.go
deleted file mode 100644
index a55da1d3c81..00000000000
--- a/libgo/go/cmd/vet/print.go
+++ /dev/null
@@ -1,1070 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file contains the printf-checker.
-
-package main
-
-import (
- "bytes"
- "encoding/gob"
- "flag"
- "fmt"
- "go/ast"
- "go/constant"
- "go/token"
- "go/types"
- "regexp"
- "sort"
- "strconv"
- "strings"
- "unicode/utf8"
-)
-
-var printfuncs = flag.String("printfuncs", "", "comma-separated list of print function names to check")
-
-func init() {
- register("printf",
- "check printf-like invocations",
- checkFmtPrintfCall,
- funcDecl, callExpr)
- registerPkgCheck("printf", findPrintfLike)
- registerExport("printf", exportPrintfLike)
- gob.Register([]printfExport(nil))
-}
-
-func initPrintFlags() {
- if *printfuncs == "" {
- return
- }
- for _, name := range strings.Split(*printfuncs, ",") {
- if len(name) == 0 {
- flag.Usage()
- }
-
- // Backwards compatibility: skip optional first argument
- // index after the colon.
- if colon := strings.LastIndex(name, ":"); colon > 0 {
- name = name[:colon]
- }
-
- if !strings.Contains(name, ".") {
- name = strings.ToLower(name)
- }
- isPrint[name] = true
- }
-}
-
-var localPrintfLike = make(map[string]int)
-
-type printfExport struct {
- Name string
- Kind int
-}
-
-// printfImported maps from package name to the printf vet data
-// exported by that package.
-var printfImported = make(map[string]map[string]int)
-
-type printfWrapper struct {
- name string
- fn *ast.FuncDecl
- format *ast.Field
- args *ast.Field
- callers []printfCaller
- failed bool // if true, not a printf wrapper
-}
-
-type printfCaller struct {
- w *printfWrapper
- call *ast.CallExpr
-}
-
-// maybePrintfWrapper decides whether decl (a declared function) may be a wrapper
-// around a fmt.Printf or fmt.Print function. If so it returns a printfWrapper
-// function describing the declaration. Later processing will analyze the
-// graph of potential printf wrappers to pick out the ones that are true wrappers.
-// A function may be a Printf or Print wrapper if its last argument is ...interface{}.
-// If the next-to-last argument is a string, then this may be a Printf wrapper.
-// Otherwise it may be a Print wrapper.
-func maybePrintfWrapper(decl ast.Decl) *printfWrapper {
- // Look for functions with final argument type ...interface{}.
- fn, ok := decl.(*ast.FuncDecl)
- if !ok || fn.Body == nil {
- return nil
- }
- name := fn.Name.Name
- if fn.Recv != nil {
- // For (*T).Name or T.name, use "T.name".
- rcvr := fn.Recv.List[0].Type
- if ptr, ok := rcvr.(*ast.StarExpr); ok {
- rcvr = ptr.X
- }
- id, ok := rcvr.(*ast.Ident)
- if !ok {
- return nil
- }
- name = id.Name + "." + name
- }
- params := fn.Type.Params.List
- if len(params) == 0 {
- return nil
- }
- args := params[len(params)-1]
- if len(args.Names) != 1 {
- return nil
- }
- ddd, ok := args.Type.(*ast.Ellipsis)
- if !ok {
- return nil
- }
- iface, ok := ddd.Elt.(*ast.InterfaceType)
- if !ok || len(iface.Methods.List) > 0 {
- return nil
- }
- var format *ast.Field
- if len(params) >= 2 {
- p := params[len(params)-2]
- if len(p.Names) == 1 {
- if id, ok := p.Type.(*ast.Ident); ok && id.Name == "string" {
- format = p
- }
- }
- }
-
- return &printfWrapper{
- name: name,
- fn: fn,
- format: format,
- args: args,
- }
-}
-
-// findPrintfLike scans the entire package to find printf-like functions.
-func findPrintfLike(pkg *Package) {
- if vcfg.ImportPath == "" { // no type or vetx information; don't bother
- return
- }
-
- // Gather potential wrappesr and call graph between them.
- byName := make(map[string]*printfWrapper)
- var wrappers []*printfWrapper
- for _, file := range pkg.files {
- if file.file == nil {
- continue
- }
- for _, decl := range file.file.Decls {
- w := maybePrintfWrapper(decl)
- if w == nil {
- continue
- }
- byName[w.name] = w
- wrappers = append(wrappers, w)
- }
- }
-
- // Walk the graph to figure out which are really printf wrappers.
- for _, w := range wrappers {
- // Scan function for calls that could be to other printf-like functions.
- ast.Inspect(w.fn.Body, func(n ast.Node) bool {
- if w.failed {
- return false
- }
-
- // TODO: Relax these checks; issue 26555.
- if assign, ok := n.(*ast.AssignStmt); ok {
- for _, lhs := range assign.Lhs {
- if match(lhs, w.format) || match(lhs, w.args) {
- // Modifies the format
- // string or args in
- // some way, so not a
- // simple wrapper.
- w.failed = true
- return false
- }
- }
- }
- if un, ok := n.(*ast.UnaryExpr); ok && un.Op == token.AND {
- if match(un.X, w.format) || match(un.X, w.args) {
- // Taking the address of the
- // format string or args,
- // so not a simple wrapper.
- w.failed = true
- return false
- }
- }
-
- call, ok := n.(*ast.CallExpr)
- if !ok || len(call.Args) == 0 || !match(call.Args[len(call.Args)-1], w.args) {
- return true
- }
-
- pkgpath, name, kind := printfNameAndKind(pkg, call.Fun)
- if kind != 0 {
- checkPrintfFwd(pkg, w, call, kind)
- return true
- }
-
- // If the call is to another function in this package,
- // maybe we will find out it is printf-like later.
- // Remember this call for later checking.
- if pkgpath == "" && byName[name] != nil {
- callee := byName[name]
- callee.callers = append(callee.callers, printfCaller{w, call})
- }
-
- return true
- })
- }
-}
-
-func match(arg ast.Expr, param *ast.Field) bool {
- id, ok := arg.(*ast.Ident)
- return ok && id.Obj != nil && id.Obj.Decl == param
-}
-
-const (
- kindPrintf = 1
- kindPrint = 2
-)
-
-// printfLike reports whether a call to fn should be considered a call to a printf-like function.
-// It returns 0 (indicating not a printf-like function), kindPrintf, or kindPrint.
-func printfLike(pkg *Package, fn ast.Expr, byName map[string]*printfWrapper) int {
- if id, ok := fn.(*ast.Ident); ok && id.Obj != nil {
- if w := byName[id.Name]; w != nil && id.Obj.Decl == w.fn {
- // Found call to function in same package.
- return localPrintfLike[id.Name]
- }
- }
- if sel, ok := fn.(*ast.SelectorExpr); ok {
- if id, ok := sel.X.(*ast.Ident); ok && id.Name == "fmt" && strings.Contains(sel.Sel.Name, "rint") {
- if strings.HasSuffix(sel.Sel.Name, "f") {
- return kindPrintf
- }
- return kindPrint
- }
- }
- return 0
-}
-
-// checkPrintfFwd checks that a printf-forwarding wrapper is forwarding correctly.
-// It diagnoses writing fmt.Printf(format, args) instead of fmt.Printf(format, args...).
-func checkPrintfFwd(pkg *Package, w *printfWrapper, call *ast.CallExpr, kind int) {
- matched := kind == kindPrint ||
- kind == kindPrintf && len(call.Args) >= 2 && match(call.Args[len(call.Args)-2], w.format)
- if !matched {
- return
- }
-
- if !call.Ellipsis.IsValid() {
- typ, ok := pkg.types[call.Fun].Type.(*types.Signature)
- if !ok {
- return
- }
- if len(call.Args) > typ.Params().Len() {
- // If we're passing more arguments than what the
- // print/printf function can take, adding an ellipsis
- // would break the program. For example:
- //
- // func foo(arg1 string, arg2 ...interface{} {
- // fmt.Printf("%s %v", arg1, arg2)
- // }
- return
- }
- if !vcfg.VetxOnly {
- desc := "printf"
- if kind == kindPrint {
- desc = "print"
- }
- pkg.files[0].Badf(call.Pos(), "missing ... in args forwarded to %s-like function", desc)
- }
- return
- }
- name := w.name
- if localPrintfLike[name] == 0 {
- localPrintfLike[name] = kind
- for _, caller := range w.callers {
- checkPrintfFwd(pkg, caller.w, caller.call, kind)
- }
- }
-}
-
-func exportPrintfLike() interface{} {
- out := make([]printfExport, 0, len(localPrintfLike))
- for name, kind := range localPrintfLike {
- out = append(out, printfExport{
- Name: name,
- Kind: kind,
- })
- }
- sort.Slice(out, func(i, j int) bool {
- return out[i].Name < out[j].Name
- })
- return out
-}
-
-// isPrint records the print functions.
-// If a key ends in 'f' then it is assumed to be a formatted print.
-var isPrint = map[string]bool{
- "fmt.Errorf": true,
- "fmt.Fprint": true,
- "fmt.Fprintf": true,
- "fmt.Fprintln": true,
- "fmt.Print": true,
- "fmt.Printf": true,
- "fmt.Println": true,
- "fmt.Sprint": true,
- "fmt.Sprintf": true,
- "fmt.Sprintln": true,
-
- // testing.B, testing.T not auto-detected
- // because the methods are picked up by embedding.
- "testing.B.Error": true,
- "testing.B.Errorf": true,
- "testing.B.Fatal": true,
- "testing.B.Fatalf": true,
- "testing.B.Log": true,
- "testing.B.Logf": true,
- "testing.B.Skip": true,
- "testing.B.Skipf": true,
- "testing.T.Error": true,
- "testing.T.Errorf": true,
- "testing.T.Fatal": true,
- "testing.T.Fatalf": true,
- "testing.T.Log": true,
- "testing.T.Logf": true,
- "testing.T.Skip": true,
- "testing.T.Skipf": true,
-
- // testing.TB is an interface, so can't detect wrapping.
- "testing.TB.Error": true,
- "testing.TB.Errorf": true,
- "testing.TB.Fatal": true,
- "testing.TB.Fatalf": true,
- "testing.TB.Log": true,
- "testing.TB.Logf": true,
- "testing.TB.Skip": true,
- "testing.TB.Skipf": true,
-}
-
-// formatString returns the format string argument and its index within
-// the given printf-like call expression.
-//
-// The last parameter before variadic arguments is assumed to be
-// a format string.
-//
-// The first string literal or string constant is assumed to be a format string
-// if the call's signature cannot be determined.
-//
-// If it cannot find any format string parameter, it returns ("", -1).
-func formatString(f *File, call *ast.CallExpr) (format string, idx int) {
- typ := f.pkg.types[call.Fun].Type
- if typ != nil {
- if sig, ok := typ.(*types.Signature); ok {
- if !sig.Variadic() {
- // Skip checking non-variadic functions.
- return "", -1
- }
- idx := sig.Params().Len() - 2
- if idx < 0 {
- // Skip checking variadic functions without
- // fixed arguments.
- return "", -1
- }
- s, ok := stringConstantArg(f, call, idx)
- if !ok {
- // The last argument before variadic args isn't a string.
- return "", -1
- }
- return s, idx
- }
- }
-
- // Cannot determine call's signature. Fall back to scanning for the first
- // string constant in the call.
- for idx := range call.Args {
- if s, ok := stringConstantArg(f, call, idx); ok {
- return s, idx
- }
- if f.pkg.types[call.Args[idx]].Type == types.Typ[types.String] {
- // Skip checking a call with a non-constant format
- // string argument, since its contents are unavailable
- // for validation.
- return "", -1
- }
- }
- return "", -1
-}
-
-// stringConstantArg returns call's string constant argument at the index idx.
-//
-// ("", false) is returned if call's argument at the index idx isn't a string
-// constant.
-func stringConstantArg(f *File, call *ast.CallExpr, idx int) (string, bool) {
- if idx >= len(call.Args) {
- return "", false
- }
- arg := call.Args[idx]
- lit := f.pkg.types[arg].Value
- if lit != nil && lit.Kind() == constant.String {
- return constant.StringVal(lit), true
- }
- return "", false
-}
-
-// checkCall triggers the print-specific checks if the call invokes a print function.
-func checkFmtPrintfCall(f *File, node ast.Node) {
- if f.pkg.typesPkg == nil {
- // This check now requires type information.
- return
- }
-
- if d, ok := node.(*ast.FuncDecl); ok && isStringer(f, d) {
- // Remember we saw this.
- if f.stringerPtrs == nil {
- f.stringerPtrs = make(map[*ast.Object]bool)
- }
- if l := d.Recv.List; len(l) == 1 {
- if n := l[0].Names; len(n) == 1 {
- typ := f.pkg.types[l[0].Type]
- _, ptrRecv := typ.Type.(*types.Pointer)
- f.stringerPtrs[n[0].Obj] = ptrRecv
- }
- }
- return
- }
-
- call, ok := node.(*ast.CallExpr)
- if !ok {
- return
- }
-
- // Construct name like pkg.Printf or pkg.Type.Printf for lookup.
- _, name, kind := printfNameAndKind(f.pkg, call.Fun)
- if kind == kindPrintf {
- f.checkPrintf(call, name)
- }
- if kind == kindPrint {
- f.checkPrint(call, name)
- }
-}
-
-func printfName(pkg *Package, called ast.Expr) (pkgpath, name string) {
- switch x := called.(type) {
- case *ast.Ident:
- if fn, ok := pkg.uses[x].(*types.Func); ok {
- if fn.Pkg() == nil || fn.Pkg() == pkg.typesPkg {
- pkgpath = ""
- } else {
- pkgpath = fn.Pkg().Path()
- }
- return pkgpath, x.Name
- }
-
- case *ast.SelectorExpr:
- // Check for "fmt.Printf".
- if id, ok := x.X.(*ast.Ident); ok {
- if pkgName, ok := pkg.uses[id].(*types.PkgName); ok {
- return pkgName.Imported().Path(), x.Sel.Name
- }
- }
-
- // Check for t.Logf where t is a *testing.T.
- if sel := pkg.selectors[x]; sel != nil {
- recv := sel.Recv()
- if p, ok := recv.(*types.Pointer); ok {
- recv = p.Elem()
- }
- if named, ok := recv.(*types.Named); ok {
- obj := named.Obj()
- if obj.Pkg() == nil || obj.Pkg() == pkg.typesPkg {
- pkgpath = ""
- } else {
- pkgpath = obj.Pkg().Path()
- }
- return pkgpath, obj.Name() + "." + x.Sel.Name
- }
- }
- }
- return "", ""
-}
-
-func printfNameAndKind(pkg *Package, called ast.Expr) (pkgpath, name string, kind int) {
- pkgpath, name = printfName(pkg, called)
- if name == "" {
- return pkgpath, name, 0
- }
-
- if pkgpath == "" {
- kind = localPrintfLike[name]
- } else if m, ok := printfImported[pkgpath]; ok {
- kind = m[name]
- } else {
- var m map[string]int
- if out, ok := readVetx(pkgpath, "printf").([]printfExport); ok {
- m = make(map[string]int)
- for _, x := range out {
- m[x.Name] = x.Kind
- }
- }
- printfImported[pkgpath] = m
- kind = m[name]
- }
-
- if kind == 0 {
- _, ok := isPrint[pkgpath+"."+name]
- if !ok {
- // Next look up just "printf", for use with -printfuncs.
- short := name[strings.LastIndex(name, ".")+1:]
- _, ok = isPrint[strings.ToLower(short)]
- }
- if ok {
- if strings.HasSuffix(name, "f") {
- kind = kindPrintf
- } else {
- kind = kindPrint
- }
- }
- }
- return pkgpath, name, kind
-}
-
-// isStringer returns true if the provided declaration is a "String() string"
-// method, an implementation of fmt.Stringer.
-func isStringer(f *File, d *ast.FuncDecl) bool {
- return d.Recv != nil && d.Name.Name == "String" && d.Type.Results != nil &&
- len(d.Type.Params.List) == 0 && len(d.Type.Results.List) == 1 &&
- f.pkg.types[d.Type.Results.List[0].Type].Type == types.Typ[types.String]
-}
-
-// isFormatter reports whether t satisfies fmt.Formatter.
-// Unlike fmt.Stringer, it's impossible to satisfy fmt.Formatter without importing fmt.
-func (f *File) isFormatter(t types.Type) bool {
- return formatterType != nil && types.Implements(t, formatterType)
-}
-
-// formatState holds the parsed representation of a printf directive such as "%3.*[4]d".
-// It is constructed by parsePrintfVerb.
-type formatState struct {
- verb rune // the format verb: 'd' for "%d"
- format string // the full format directive from % through verb, "%.3d".
- name string // Printf, Sprintf etc.
- flags []byte // the list of # + etc.
- argNums []int // the successive argument numbers that are consumed, adjusted to refer to actual arg in call
- firstArg int // Index of first argument after the format in the Printf call.
- // Used only during parse.
- file *File
- call *ast.CallExpr
- argNum int // Which argument we're expecting to format now.
- hasIndex bool // Whether the argument is indexed.
- indexPending bool // Whether we have an indexed argument that has not resolved.
- nbytes int // number of bytes of the format string consumed.
-}
-
-// checkPrintf checks a call to a formatted print routine such as Printf.
-func (f *File) checkPrintf(call *ast.CallExpr, name string) {
- format, idx := formatString(f, call)
- if idx < 0 {
- if *verbose {
- f.Warn(call.Pos(), "can't check non-constant format in call to", name)
- }
- return
- }
-
- firstArg := idx + 1 // Arguments are immediately after format string.
- if !strings.Contains(format, "%") {
- if len(call.Args) > firstArg {
- f.Badf(call.Pos(), "%s call has arguments but no formatting directives", name)
- }
- return
- }
- // Hard part: check formats against args.
- argNum := firstArg
- maxArgNum := firstArg
- anyIndex := false
- for i, w := 0, 0; i < len(format); i += w {
- w = 1
- if format[i] != '%' {
- continue
- }
- state := f.parsePrintfVerb(call, name, format[i:], firstArg, argNum)
- if state == nil {
- return
- }
- w = len(state.format)
- if !f.okPrintfArg(call, state) { // One error per format is enough.
- return
- }
- if state.hasIndex {
- anyIndex = true
- }
- if len(state.argNums) > 0 {
- // Continue with the next sequential argument.
- argNum = state.argNums[len(state.argNums)-1] + 1
- }
- for _, n := range state.argNums {
- if n >= maxArgNum {
- maxArgNum = n + 1
- }
- }
- }
- // Dotdotdot is hard.
- if call.Ellipsis.IsValid() && maxArgNum >= len(call.Args)-1 {
- return
- }
- // If any formats are indexed, extra arguments are ignored.
- if anyIndex {
- return
- }
- // There should be no leftover arguments.
- if maxArgNum != len(call.Args) {
- expect := maxArgNum - firstArg
- numArgs := len(call.Args) - firstArg
- f.Badf(call.Pos(), "%s call needs %v but has %v", name, count(expect, "arg"), count(numArgs, "arg"))
- }
-}
-
-// parseFlags accepts any printf flags.
-func (s *formatState) parseFlags() {
- for s.nbytes < len(s.format) {
- switch c := s.format[s.nbytes]; c {
- case '#', '0', '+', '-', ' ':
- s.flags = append(s.flags, c)
- s.nbytes++
- default:
- return
- }
- }
-}
-
-// scanNum advances through a decimal number if present.
-func (s *formatState) scanNum() {
- for ; s.nbytes < len(s.format); s.nbytes++ {
- c := s.format[s.nbytes]
- if c < '0' || '9' < c {
- return
- }
- }
-}
-
-// parseIndex scans an index expression. It returns false if there is a syntax error.
-func (s *formatState) parseIndex() bool {
- if s.nbytes == len(s.format) || s.format[s.nbytes] != '[' {
- return true
- }
- // Argument index present.
- s.nbytes++ // skip '['
- start := s.nbytes
- s.scanNum()
- ok := true
- if s.nbytes == len(s.format) || s.nbytes == start || s.format[s.nbytes] != ']' {
- ok = false
- s.nbytes = strings.Index(s.format, "]")
- if s.nbytes < 0 {
- s.file.Badf(s.call.Pos(), "%s format %s is missing closing ]", s.name, s.format)
- return false
- }
- }
- arg32, err := strconv.ParseInt(s.format[start:s.nbytes], 10, 32)
- if err != nil || !ok || arg32 <= 0 || arg32 > int64(len(s.call.Args)-s.firstArg) {
- s.file.Badf(s.call.Pos(), "%s format has invalid argument index [%s]", s.name, s.format[start:s.nbytes])
- return false
- }
- s.nbytes++ // skip ']'
- arg := int(arg32)
- arg += s.firstArg - 1 // We want to zero-index the actual arguments.
- s.argNum = arg
- s.hasIndex = true
- s.indexPending = true
- return true
-}
-
-// parseNum scans a width or precision (or *). It returns false if there's a bad index expression.
-func (s *formatState) parseNum() bool {
- if s.nbytes < len(s.format) && s.format[s.nbytes] == '*' {
- if s.indexPending { // Absorb it.
- s.indexPending = false
- }
- s.nbytes++
- s.argNums = append(s.argNums, s.argNum)
- s.argNum++
- } else {
- s.scanNum()
- }
- return true
-}
-
-// parsePrecision scans for a precision. It returns false if there's a bad index expression.
-func (s *formatState) parsePrecision() bool {
- // If there's a period, there may be a precision.
- if s.nbytes < len(s.format) && s.format[s.nbytes] == '.' {
- s.flags = append(s.flags, '.') // Treat precision as a flag.
- s.nbytes++
- if !s.parseIndex() {
- return false
- }
- if !s.parseNum() {
- return false
- }
- }
- return true
-}
-
-// parsePrintfVerb looks the formatting directive that begins the format string
-// and returns a formatState that encodes what the directive wants, without looking
-// at the actual arguments present in the call. The result is nil if there is an error.
-func (f *File) parsePrintfVerb(call *ast.CallExpr, name, format string, firstArg, argNum int) *formatState {
- state := &formatState{
- format: format,
- name: name,
- flags: make([]byte, 0, 5),
- argNum: argNum,
- argNums: make([]int, 0, 1),
- nbytes: 1, // There's guaranteed to be a percent sign.
- firstArg: firstArg,
- file: f,
- call: call,
- }
- // There may be flags.
- state.parseFlags()
- // There may be an index.
- if !state.parseIndex() {
- return nil
- }
- // There may be a width.
- if !state.parseNum() {
- return nil
- }
- // There may be a precision.
- if !state.parsePrecision() {
- return nil
- }
- // Now a verb, possibly prefixed by an index (which we may already have).
- if !state.indexPending && !state.parseIndex() {
- return nil
- }
- if state.nbytes == len(state.format) {
- f.Badf(call.Pos(), "%s format %s is missing verb at end of string", name, state.format)
- return nil
- }
- verb, w := utf8.DecodeRuneInString(state.format[state.nbytes:])
- state.verb = verb
- state.nbytes += w
- if verb != '%' {
- state.argNums = append(state.argNums, state.argNum)
- }
- state.format = state.format[:state.nbytes]
- return state
-}
-
-// printfArgType encodes the types of expressions a printf verb accepts. It is a bitmask.
-type printfArgType int
-
-const (
- argBool printfArgType = 1 << iota
- argInt
- argRune
- argString
- argFloat
- argComplex
- argPointer
- anyType printfArgType = ^0
-)
-
-type printVerb struct {
- verb rune // User may provide verb through Formatter; could be a rune.
- flags string // known flags are all ASCII
- typ printfArgType
-}
-
-// Common flag sets for printf verbs.
-const (
- noFlag = ""
- numFlag = " -+.0"
- sharpNumFlag = " -+.0#"
- allFlags = " -+.0#"
-)
-
-// printVerbs identifies which flags are known to printf for each verb.
-var printVerbs = []printVerb{
- // '-' is a width modifier, always valid.
- // '.' is a precision for float, max width for strings.
- // '+' is required sign for numbers, Go format for %v.
- // '#' is alternate format for several verbs.
- // ' ' is spacer for numbers
- {'%', noFlag, 0},
- {'b', numFlag, argInt | argFloat | argComplex},
- {'c', "-", argRune | argInt},
- {'d', numFlag, argInt | argPointer},
- {'e', sharpNumFlag, argFloat | argComplex},
- {'E', sharpNumFlag, argFloat | argComplex},
- {'f', sharpNumFlag, argFloat | argComplex},
- {'F', sharpNumFlag, argFloat | argComplex},
- {'g', sharpNumFlag, argFloat | argComplex},
- {'G', sharpNumFlag, argFloat | argComplex},
- {'o', sharpNumFlag, argInt},
- {'p', "-#", argPointer},
- {'q', " -+.0#", argRune | argInt | argString},
- {'s', " -+.0", argString},
- {'t', "-", argBool},
- {'T', "-", anyType},
- {'U', "-#", argRune | argInt},
- {'v', allFlags, anyType},
- {'x', sharpNumFlag, argRune | argInt | argString | argPointer},
- {'X', sharpNumFlag, argRune | argInt | argString | argPointer},
-}
-
-// okPrintfArg compares the formatState to the arguments actually present,
-// reporting any discrepancies it can discern. If the final argument is ellipsissed,
-// there's little it can do for that.
-func (f *File) okPrintfArg(call *ast.CallExpr, state *formatState) (ok bool) {
- var v printVerb
- found := false
- // Linear scan is fast enough for a small list.
- for _, v = range printVerbs {
- if v.verb == state.verb {
- found = true
- break
- }
- }
-
- // Does current arg implement fmt.Formatter?
- formatter := false
- if state.argNum < len(call.Args) {
- if tv, ok := f.pkg.types[call.Args[state.argNum]]; ok {
- formatter = f.isFormatter(tv.Type)
- }
- }
-
- if !formatter {
- if !found {
- f.Badf(call.Pos(), "%s format %s has unknown verb %c", state.name, state.format, state.verb)
- return false
- }
- for _, flag := range state.flags {
- // TODO: Disable complaint about '0' for Go 1.10. To be fixed properly in 1.11.
- // See issues 23598 and 23605.
- if flag == '0' {
- continue
- }
- if !strings.ContainsRune(v.flags, rune(flag)) {
- f.Badf(call.Pos(), "%s format %s has unrecognized flag %c", state.name, state.format, flag)
- return false
- }
- }
- }
- // Verb is good. If len(state.argNums)>trueArgs, we have something like %.*s and all
- // but the final arg must be an integer.
- trueArgs := 1
- if state.verb == '%' {
- trueArgs = 0
- }
- nargs := len(state.argNums)
- for i := 0; i < nargs-trueArgs; i++ {
- argNum := state.argNums[i]
- if !f.argCanBeChecked(call, i, state) {
- return
- }
- arg := call.Args[argNum]
- if !f.matchArgType(argInt, nil, arg) {
- f.Badf(call.Pos(), "%s format %s uses non-int %s as argument of *", state.name, state.format, f.gofmt(arg))
- return false
- }
- }
- if state.verb == '%' || formatter {
- return true
- }
- argNum := state.argNums[len(state.argNums)-1]
- if !f.argCanBeChecked(call, len(state.argNums)-1, state) {
- return false
- }
- arg := call.Args[argNum]
- if f.isFunctionValue(arg) && state.verb != 'p' && state.verb != 'T' {
- f.Badf(call.Pos(), "%s format %s arg %s is a func value, not called", state.name, state.format, f.gofmt(arg))
- return false
- }
- if !f.matchArgType(v.typ, nil, arg) {
- typeString := ""
- if typ := f.pkg.types[arg].Type; typ != nil {
- typeString = typ.String()
- }
- f.Badf(call.Pos(), "%s format %s has arg %s of wrong type %s", state.name, state.format, f.gofmt(arg), typeString)
- return false
- }
- if v.typ&argString != 0 && v.verb != 'T' && !bytes.Contains(state.flags, []byte{'#'}) && f.recursiveStringer(arg) {
- f.Badf(call.Pos(), "%s format %s with arg %s causes recursive String method call", state.name, state.format, f.gofmt(arg))
- return false
- }
- return true
-}
-
-// recursiveStringer reports whether the provided argument is r or &r for the
-// fmt.Stringer receiver identifier r.
-func (f *File) recursiveStringer(e ast.Expr) bool {
- if len(f.stringerPtrs) == 0 {
- return false
- }
- ptr := false
- var obj *ast.Object
- switch e := e.(type) {
- case *ast.Ident:
- obj = e.Obj
- case *ast.UnaryExpr:
- if id, ok := e.X.(*ast.Ident); ok && e.Op == token.AND {
- obj = id.Obj
- ptr = true
- }
- }
-
- // It's unlikely to be a recursive stringer if it has a Format method.
- if typ := f.pkg.types[e].Type; typ != nil {
- if f.isFormatter(typ) {
- return false
- }
- }
-
- // We compare the underlying Object, which checks that the identifier
- // is the one we declared as the receiver for the String method in
- // which this printf appears.
- ptrRecv, exist := f.stringerPtrs[obj]
- if !exist {
- return false
- }
- // We also need to check that using &t when we declared String
- // on (t *T) is ok; in such a case, the address is printed.
- if ptr && ptrRecv {
- return false
- }
- return true
-}
-
-// isFunctionValue reports whether the expression is a function as opposed to a function call.
-// It is almost always a mistake to print a function value.
-func (f *File) isFunctionValue(e ast.Expr) bool {
- if typ := f.pkg.types[e].Type; typ != nil {
- _, ok := typ.(*types.Signature)
- return ok
- }
- return false
-}
-
-// argCanBeChecked reports whether the specified argument is statically present;
-// it may be beyond the list of arguments or in a terminal slice... argument, which
-// means we can't see it.
-func (f *File) argCanBeChecked(call *ast.CallExpr, formatArg int, state *formatState) bool {
- argNum := state.argNums[formatArg]
- if argNum <= 0 {
- // Shouldn't happen, so catch it with prejudice.
- panic("negative arg num")
- }
- if argNum < len(call.Args)-1 {
- return true // Always OK.
- }
- if call.Ellipsis.IsValid() {
- return false // We just can't tell; there could be many more arguments.
- }
- if argNum < len(call.Args) {
- return true
- }
- // There are bad indexes in the format or there are fewer arguments than the format needs.
- // This is the argument number relative to the format: Printf("%s", "hi") will give 1 for the "hi".
- arg := argNum - state.firstArg + 1 // People think of arguments as 1-indexed.
- f.Badf(call.Pos(), "%s format %s reads arg #%d, but call has %v", state.name, state.format, arg, count(len(call.Args)-state.firstArg, "arg"))
- return false
-}
-
-// printFormatRE is the regexp we match and report as a possible format string
-// in the first argument to unformatted prints like fmt.Print.
-// We exclude the space flag, so that printing a string like "x % y" is not reported as a format.
-var printFormatRE = regexp.MustCompile(`%` + flagsRE + numOptRE + `\.?` + numOptRE + indexOptRE + verbRE)
-
-const (
- flagsRE = `[+\-#]*`
- indexOptRE = `(\[[0-9]+\])?`
- numOptRE = `([0-9]+|` + indexOptRE + `\*)?`
- verbRE = `[bcdefgopqstvxEFGTUX]`
-)
-
-// checkPrint checks a call to an unformatted print routine such as Println.
-func (f *File) checkPrint(call *ast.CallExpr, name string) {
- firstArg := 0
- typ := f.pkg.types[call.Fun].Type
- if typ == nil {
- // Skip checking functions with unknown type.
- return
- }
- if sig, ok := typ.(*types.Signature); ok {
- if !sig.Variadic() {
- // Skip checking non-variadic functions.
- return
- }
- params := sig.Params()
- firstArg = params.Len() - 1
-
- typ := params.At(firstArg).Type()
- typ = typ.(*types.Slice).Elem()
- it, ok := typ.(*types.Interface)
- if !ok || !it.Empty() {
- // Skip variadic functions accepting non-interface{} args.
- return
- }
- }
- args := call.Args
- if len(args) <= firstArg {
- // Skip calls without variadic args.
- return
- }
- args = args[firstArg:]
-
- if firstArg == 0 {
- if sel, ok := call.Args[0].(*ast.SelectorExpr); ok {
- if x, ok := sel.X.(*ast.Ident); ok {
- if x.Name == "os" && strings.HasPrefix(sel.Sel.Name, "Std") {
- f.Badf(call.Pos(), "%s does not take io.Writer but has first arg %s", name, f.gofmt(call.Args[0]))
- }
- }
- }
- }
-
- arg := args[0]
- if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
- // Ignore trailing % character in lit.Value.
- // The % in "abc 0.0%" couldn't be a formatting directive.
- s := strings.TrimSuffix(lit.Value, `%"`)
- if strings.Contains(s, "%") {
- m := printFormatRE.FindStringSubmatch(s)
- if m != nil {
- f.Badf(call.Pos(), "%s call has possible formatting directive %s", name, m[0])
- }
- }
- }
- if strings.HasSuffix(name, "ln") {
- // The last item, if a string, should not have a newline.
- arg = args[len(args)-1]
- if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
- str, _ := strconv.Unquote(lit.Value)
- if strings.HasSuffix(str, "\n") {
- f.Badf(call.Pos(), "%s arg list ends with redundant newline", name)
- }
- }
- }
- for _, arg := range args {
- if f.isFunctionValue(arg) {
- f.Badf(call.Pos(), "%s arg %s is a func value, not called", name, f.gofmt(arg))
- }
- if f.recursiveStringer(arg) {
- f.Badf(call.Pos(), "%s arg %s causes recursive call to String method", name, f.gofmt(arg))
- }
- }
-}
-
-// count(n, what) returns "1 what" or "N whats"
-// (assuming the plural of what is whats).
-func count(n int, what string) string {
- if n == 1 {
- return "1 " + what
- }
- return fmt.Sprintf("%d %ss", n, what)
-}
diff --git a/libgo/go/cmd/vet/rangeloop.go b/libgo/go/cmd/vet/rangeloop.go
deleted file mode 100644
index 53a41364dfe..00000000000
--- a/libgo/go/cmd/vet/rangeloop.go
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-This file contains the code to check range loop variables bound inside function
-literals that are deferred or launched in new goroutines. We only check
-instances where the defer or go statement is the last statement in the loop
-body, as otherwise we would need whole program analysis.
-
-For example:
-
- for i, v := range s {
- go func() {
- println(i, v) // not what you might expect
- }()
- }
-
-See: https://golang.org/doc/go_faq.html#closures_and_goroutines
-*/
-
-package main
-
-import "go/ast"
-
-func init() {
- register("rangeloops",
- "check that loop variables are used correctly",
- checkLoop,
- rangeStmt, forStmt)
-}
-
-// checkLoop walks the body of the provided loop statement, checking whether
-// its index or value variables are used unsafely inside goroutines or deferred
-// function literals.
-func checkLoop(f *File, node ast.Node) {
- // Find the variables updated by the loop statement.
- var vars []*ast.Ident
- addVar := func(expr ast.Expr) {
- if id, ok := expr.(*ast.Ident); ok {
- vars = append(vars, id)
- }
- }
- var body *ast.BlockStmt
- switch n := node.(type) {
- case *ast.RangeStmt:
- body = n.Body
- addVar(n.Key)
- addVar(n.Value)
- case *ast.ForStmt:
- body = n.Body
- switch post := n.Post.(type) {
- case *ast.AssignStmt:
- // e.g. for p = head; p != nil; p = p.next
- for _, lhs := range post.Lhs {
- addVar(lhs)
- }
- case *ast.IncDecStmt:
- // e.g. for i := 0; i < n; i++
- addVar(post.X)
- }
- }
- if vars == nil {
- return
- }
-
- // Inspect a go or defer statement
- // if it's the last one in the loop body.
- // (We give up if there are following statements,
- // because it's hard to prove go isn't followed by wait,
- // or defer by return.)
- if len(body.List) == 0 {
- return
- }
- var last *ast.CallExpr
- switch s := body.List[len(body.List)-1].(type) {
- case *ast.GoStmt:
- last = s.Call
- case *ast.DeferStmt:
- last = s.Call
- default:
- return
- }
- lit, ok := last.Fun.(*ast.FuncLit)
- if !ok {
- return
- }
- ast.Inspect(lit.Body, func(n ast.Node) bool {
- id, ok := n.(*ast.Ident)
- if !ok || id.Obj == nil {
- return true
- }
- if f.pkg.types[id].Type == nil {
- // Not referring to a variable (e.g. struct field name)
- return true
- }
- for _, v := range vars {
- if v.Obj == id.Obj {
- f.Badf(id.Pos(), "loop variable %s captured by func literal",
- id.Name)
- }
- }
- return true
- })
-}
diff --git a/libgo/go/cmd/vet/shadow.go b/libgo/go/cmd/vet/shadow.go
deleted file mode 100644
index 29c952fd885..00000000000
--- a/libgo/go/cmd/vet/shadow.go
+++ /dev/null
@@ -1,246 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-This file contains the code to check for shadowed variables.
-A shadowed variable is a variable declared in an inner scope
-with the same name and type as a variable in an outer scope,
-and where the outer variable is mentioned after the inner one
-is declared.
-
-(This definition can be refined; the module generates too many
-false positives and is not yet enabled by default.)
-
-For example:
-
- func BadRead(f *os.File, buf []byte) error {
- var err error
- for {
- n, err := f.Read(buf) // shadows the function variable 'err'
- if err != nil {
- break // causes return of wrong value
- }
- foo(buf)
- }
- return err
- }
-
-*/
-
-package main
-
-import (
- "flag"
- "go/ast"
- "go/token"
- "go/types"
-)
-
-var strictShadowing = flag.Bool("shadowstrict", false, "whether to be strict about shadowing; can be noisy")
-
-func init() {
- register("shadow",
- "check for shadowed variables (experimental; must be set explicitly)",
- checkShadow,
- assignStmt, genDecl)
- experimental["shadow"] = true
-}
-
-func checkShadow(f *File, node ast.Node) {
- switch n := node.(type) {
- case *ast.AssignStmt:
- checkShadowAssignment(f, n)
- case *ast.GenDecl:
- checkShadowDecl(f, n)
- }
-}
-
-// Span stores the minimum range of byte positions in the file in which a
-// given variable (types.Object) is mentioned. It is lexically defined: it spans
-// from the beginning of its first mention to the end of its last mention.
-// A variable is considered shadowed (if *strictShadowing is off) only if the
-// shadowing variable is declared within the span of the shadowed variable.
-// In other words, if a variable is shadowed but not used after the shadowed
-// variable is declared, it is inconsequential and not worth complaining about.
-// This simple check dramatically reduces the nuisance rate for the shadowing
-// check, at least until something cleverer comes along.
-//
-// One wrinkle: A "naked return" is a silent use of a variable that the Span
-// will not capture, but the compilers catch naked returns of shadowed
-// variables so we don't need to.
-//
-// Cases this gets wrong (TODO):
-// - If a for loop's continuation statement mentions a variable redeclared in
-// the block, we should complain about it but don't.
-// - A variable declared inside a function literal can falsely be identified
-// as shadowing a variable in the outer function.
-//
-type Span struct {
- min token.Pos
- max token.Pos
-}
-
-// contains reports whether the position is inside the span.
-func (s Span) contains(pos token.Pos) bool {
- return s.min <= pos && pos < s.max
-}
-
-// growSpan expands the span for the object to contain the instance represented
-// by the identifier.
-func (pkg *Package) growSpan(ident *ast.Ident, obj types.Object) {
- if *strictShadowing {
- return // No need
- }
- pos := ident.Pos()
- end := ident.End()
- span, ok := pkg.spans[obj]
- if ok {
- if span.min > pos {
- span.min = pos
- }
- if span.max < end {
- span.max = end
- }
- } else {
- span = Span{pos, end}
- }
- pkg.spans[obj] = span
-}
-
-// checkShadowAssignment checks for shadowing in a short variable declaration.
-func checkShadowAssignment(f *File, a *ast.AssignStmt) {
- if a.Tok != token.DEFINE {
- return
- }
- if f.idiomaticShortRedecl(a) {
- return
- }
- for _, expr := range a.Lhs {
- ident, ok := expr.(*ast.Ident)
- if !ok {
- f.Badf(expr.Pos(), "invalid AST: short variable declaration of non-identifier")
- return
- }
- checkShadowing(f, ident)
- }
-}
-
-// idiomaticShortRedecl reports whether this short declaration can be ignored for
-// the purposes of shadowing, that is, that any redeclarations it contains are deliberate.
-func (f *File) idiomaticShortRedecl(a *ast.AssignStmt) bool {
- // Don't complain about deliberate redeclarations of the form
- // i := i
- // Such constructs are idiomatic in range loops to create a new variable
- // for each iteration. Another example is
- // switch n := n.(type)
- if len(a.Rhs) != len(a.Lhs) {
- return false
- }
- // We know it's an assignment, so the LHS must be all identifiers. (We check anyway.)
- for i, expr := range a.Lhs {
- lhs, ok := expr.(*ast.Ident)
- if !ok {
- f.Badf(expr.Pos(), "invalid AST: short variable declaration of non-identifier")
- return true // Don't do any more processing.
- }
- switch rhs := a.Rhs[i].(type) {
- case *ast.Ident:
- if lhs.Name != rhs.Name {
- return false
- }
- case *ast.TypeAssertExpr:
- if id, ok := rhs.X.(*ast.Ident); ok {
- if lhs.Name != id.Name {
- return false
- }
- }
- default:
- return false
- }
- }
- return true
-}
-
-// idiomaticRedecl reports whether this declaration spec can be ignored for
-// the purposes of shadowing, that is, that any redeclarations it contains are deliberate.
-func (f *File) idiomaticRedecl(d *ast.ValueSpec) bool {
- // Don't complain about deliberate redeclarations of the form
- // var i, j = i, j
- if len(d.Names) != len(d.Values) {
- return false
- }
- for i, lhs := range d.Names {
- if rhs, ok := d.Values[i].(*ast.Ident); ok {
- if lhs.Name != rhs.Name {
- return false
- }
- }
- }
- return true
-}
-
-// checkShadowDecl checks for shadowing in a general variable declaration.
-func checkShadowDecl(f *File, d *ast.GenDecl) {
- if d.Tok != token.VAR {
- return
- }
- for _, spec := range d.Specs {
- valueSpec, ok := spec.(*ast.ValueSpec)
- if !ok {
- f.Badf(spec.Pos(), "invalid AST: var GenDecl not ValueSpec")
- return
- }
- // Don't complain about deliberate redeclarations of the form
- // var i = i
- if f.idiomaticRedecl(valueSpec) {
- return
- }
- for _, ident := range valueSpec.Names {
- checkShadowing(f, ident)
- }
- }
-}
-
-// checkShadowing checks whether the identifier shadows an identifier in an outer scope.
-func checkShadowing(f *File, ident *ast.Ident) {
- if ident.Name == "_" {
- // Can't shadow the blank identifier.
- return
- }
- obj := f.pkg.defs[ident]
- if obj == nil {
- return
- }
- // obj.Parent.Parent is the surrounding scope. If we can find another declaration
- // starting from there, we have a shadowed identifier.
- _, shadowed := obj.Parent().Parent().LookupParent(obj.Name(), obj.Pos())
- if shadowed == nil {
- return
- }
- // Don't complain if it's shadowing a universe-declared identifier; that's fine.
- if shadowed.Parent() == types.Universe {
- return
- }
- if *strictShadowing {
- // The shadowed identifier must appear before this one to be an instance of shadowing.
- if shadowed.Pos() > ident.Pos() {
- return
- }
- } else {
- // Don't complain if the span of validity of the shadowed identifier doesn't include
- // the shadowing identifier.
- span, ok := f.pkg.spans[shadowed]
- if !ok {
- f.Badf(ident.Pos(), "internal error: no range for %q", ident.Name)
- return
- }
- if !span.contains(ident.Pos()) {
- return
- }
- }
- // Don't complain if the types differ: that implies the programmer really wants two different things.
- if types.Identical(obj.Type(), shadowed.Type()) {
- f.Badf(ident.Pos(), "declaration of %q shadows declaration at %s", obj.Name(), f.loc(shadowed.Pos()))
- }
-}
diff --git a/libgo/go/cmd/vet/shift.go b/libgo/go/cmd/vet/shift.go
deleted file mode 100644
index 1e48d325242..00000000000
--- a/libgo/go/cmd/vet/shift.go
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-This file contains the code to check for suspicious shifts.
-*/
-
-package main
-
-import (
- "go/ast"
- "go/constant"
- "go/token"
- "go/types"
-)
-
-func init() {
- register("shift",
- "check for useless shifts",
- checkShift,
- binaryExpr, assignStmt)
-}
-
-func checkShift(f *File, node ast.Node) {
- if f.dead[node] {
- // Skip shift checks on unreachable nodes.
- return
- }
-
- switch node := node.(type) {
- case *ast.BinaryExpr:
- if node.Op == token.SHL || node.Op == token.SHR {
- checkLongShift(f, node, node.X, node.Y)
- }
- case *ast.AssignStmt:
- if len(node.Lhs) != 1 || len(node.Rhs) != 1 {
- return
- }
- if node.Tok == token.SHL_ASSIGN || node.Tok == token.SHR_ASSIGN {
- checkLongShift(f, node, node.Lhs[0], node.Rhs[0])
- }
- }
-}
-
-// checkLongShift checks if shift or shift-assign operations shift by more than
-// the length of the underlying variable.
-func checkLongShift(f *File, node ast.Node, x, y ast.Expr) {
- if f.pkg.types[x].Value != nil {
- // Ignore shifts of constants.
- // These are frequently used for bit-twiddling tricks
- // like ^uint(0) >> 63 for 32/64 bit detection and compatibility.
- return
- }
-
- v := f.pkg.types[y].Value
- if v == nil {
- return
- }
- amt, ok := constant.Int64Val(v)
- if !ok {
- return
- }
- t := f.pkg.types[x].Type
- if t == nil {
- return
- }
- b, ok := t.Underlying().(*types.Basic)
- if !ok {
- return
- }
- var size int64
- switch b.Kind() {
- case types.Uint8, types.Int8:
- size = 8
- case types.Uint16, types.Int16:
- size = 16
- case types.Uint32, types.Int32:
- size = 32
- case types.Uint64, types.Int64:
- size = 64
- case types.Int, types.Uint:
- size = uintBitSize
- case types.Uintptr:
- size = uintptrBitSize
- default:
- return
- }
- if amt >= size {
- ident := f.gofmt(x)
- f.Badf(node.Pos(), "%s (%d bits) too small for shift of %d", ident, size, amt)
- }
-}
-
-var (
- uintBitSize = 8 * archSizes.Sizeof(types.Typ[types.Uint])
- uintptrBitSize = 8 * archSizes.Sizeof(types.Typ[types.Uintptr])
-)
diff --git a/libgo/go/cmd/vet/structtag.go b/libgo/go/cmd/vet/structtag.go
deleted file mode 100644
index 3bc30c47405..00000000000
--- a/libgo/go/cmd/vet/structtag.go
+++ /dev/null
@@ -1,226 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file contains the test for canonical struct tags.
-
-package main
-
-import (
- "errors"
- "go/ast"
- "go/token"
- "reflect"
- "strconv"
- "strings"
-)
-
-func init() {
- register("structtags",
- "check that struct field tags have canonical format and apply to exported fields as needed",
- checkStructFieldTags,
- structType)
-}
-
-// checkStructFieldTags checks all the field tags of a struct, including checking for duplicates.
-func checkStructFieldTags(f *File, node ast.Node) {
- var seen map[[2]string]token.Pos
- for _, field := range node.(*ast.StructType).Fields.List {
- checkCanonicalFieldTag(f, field, &seen)
- }
-}
-
-var checkTagDups = []string{"json", "xml"}
-var checkTagSpaces = map[string]bool{"json": true, "xml": true, "asn1": true}
-
-// checkCanonicalFieldTag checks a single struct field tag.
-func checkCanonicalFieldTag(f *File, field *ast.Field, seen *map[[2]string]token.Pos) {
- if field.Tag == nil {
- return
- }
-
- tag, err := strconv.Unquote(field.Tag.Value)
- if err != nil {
- f.Badf(field.Pos(), "unable to read struct tag %s", field.Tag.Value)
- return
- }
-
- if err := validateStructTag(tag); err != nil {
- raw, _ := strconv.Unquote(field.Tag.Value) // field.Tag.Value is known to be a quoted string
- f.Badf(field.Pos(), "struct field tag %#q not compatible with reflect.StructTag.Get: %s", raw, err)
- }
-
- for _, key := range checkTagDups {
- val := reflect.StructTag(tag).Get(key)
- if val == "" || val == "-" || val[0] == ',' {
- continue
- }
- if key == "xml" && len(field.Names) > 0 && field.Names[0].Name == "XMLName" {
- // XMLName defines the XML element name of the struct being
- // checked. That name cannot collide with element or attribute
- // names defined on other fields of the struct. Vet does not have a
- // check for untagged fields of type struct defining their own name
- // by containing a field named XMLName; see issue 18256.
- continue
- }
- if i := strings.Index(val, ","); i >= 0 {
- if key == "xml" {
- // Use a separate namespace for XML attributes.
- for _, opt := range strings.Split(val[i:], ",") {
- if opt == "attr" {
- key += " attribute" // Key is part of the error message.
- break
- }
- }
- }
- val = val[:i]
- }
- if *seen == nil {
- *seen = map[[2]string]token.Pos{}
- }
- if pos, ok := (*seen)[[2]string{key, val}]; ok {
- var name string
- if len(field.Names) > 0 {
- name = field.Names[0].Name
- } else {
- name = field.Type.(*ast.Ident).Name
- }
- f.Badf(field.Pos(), "struct field %s repeats %s tag %q also at %s", name, key, val, f.loc(pos))
- } else {
- (*seen)[[2]string{key, val}] = field.Pos()
- }
- }
-
- // Check for use of json or xml tags with unexported fields.
-
- // Embedded struct. Nothing to do for now, but that
- // may change, depending on what happens with issue 7363.
- if len(field.Names) == 0 {
- return
- }
-
- if field.Names[0].IsExported() {
- return
- }
-
- for _, enc := range [...]string{"json", "xml"} {
- if reflect.StructTag(tag).Get(enc) != "" {
- f.Badf(field.Pos(), "struct field %s has %s tag but is not exported", field.Names[0].Name, enc)
- return
- }
- }
-}
-
-var (
- errTagSyntax = errors.New("bad syntax for struct tag pair")
- errTagKeySyntax = errors.New("bad syntax for struct tag key")
- errTagValueSyntax = errors.New("bad syntax for struct tag value")
- errTagValueSpace = errors.New("suspicious space in struct tag value")
- errTagSpace = errors.New("key:\"value\" pairs not separated by spaces")
-)
-
-// validateStructTag parses the struct tag and returns an error if it is not
-// in the canonical format, which is a space-separated list of key:"value"
-// settings. The value may contain spaces.
-func validateStructTag(tag string) error {
- // This code is based on the StructTag.Get code in package reflect.
-
- n := 0
- for ; tag != ""; n++ {
- if n > 0 && tag != "" && tag[0] != ' ' {
- // More restrictive than reflect, but catches likely mistakes
- // like `x:"foo",y:"bar"`, which parses as `x:"foo" ,y:"bar"` with second key ",y".
- return errTagSpace
- }
- // Skip leading space.
- i := 0
- for i < len(tag) && tag[i] == ' ' {
- i++
- }
- tag = tag[i:]
- if tag == "" {
- break
- }
-
- // Scan to colon. A space, a quote or a control character is a syntax error.
- // Strictly speaking, control chars include the range [0x7f, 0x9f], not just
- // [0x00, 0x1f], but in practice, we ignore the multi-byte control characters
- // as it is simpler to inspect the tag's bytes than the tag's runes.
- i = 0
- for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f {
- i++
- }
- if i == 0 {
- return errTagKeySyntax
- }
- if i+1 >= len(tag) || tag[i] != ':' {
- return errTagSyntax
- }
- if tag[i+1] != '"' {
- return errTagValueSyntax
- }
- key := tag[:i]
- tag = tag[i+1:]
-
- // Scan quoted string to find value.
- i = 1
- for i < len(tag) && tag[i] != '"' {
- if tag[i] == '\\' {
- i++
- }
- i++
- }
- if i >= len(tag) {
- return errTagValueSyntax
- }
- qvalue := tag[:i+1]
- tag = tag[i+1:]
-
- value, err := strconv.Unquote(qvalue)
- if err != nil {
- return errTagValueSyntax
- }
-
- if !checkTagSpaces[key] {
- continue
- }
-
- switch key {
- case "xml":
- // If the first or last character in the XML tag is a space, it is
- // suspicious.
- if strings.Trim(value, " ") != value {
- return errTagValueSpace
- }
-
- // If there are multiple spaces, they are suspicious.
- if strings.Count(value, " ") > 1 {
- return errTagValueSpace
- }
-
- // If there is no comma, skip the rest of the checks.
- comma := strings.IndexRune(value, ',')
- if comma < 0 {
- continue
- }
-
- // If the character before a comma is a space, this is suspicious.
- if comma > 0 && value[comma-1] == ' ' {
- return errTagValueSpace
- }
- value = value[comma+1:]
- case "json":
- // JSON allows using spaces in the name, so skip it.
- comma := strings.IndexRune(value, ',')
- if comma < 0 {
- continue
- }
- value = value[comma+1:]
- }
-
- if strings.IndexByte(value, ' ') >= 0 {
- return errTagValueSpace
- }
- }
- return nil
-}
diff --git a/libgo/go/cmd/vet/testdata/asm/asm.go b/libgo/go/cmd/vet/testdata/asm/asm.go
deleted file mode 100644
index 2237ddc3b05..00000000000
--- a/libgo/go/cmd/vet/testdata/asm/asm.go
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-// This file contains declarations to test the assembly in test_asm.s.
-
-package testdata
-
-type S struct {
- i int32
- b bool
- s string
-}
-
-func arg1(x int8, y uint8)
-func arg2(x int16, y uint16)
-func arg4(x int32, y uint32)
-func arg8(x int64, y uint64)
-func argint(x int, y uint)
-func argptr(x *byte, y *byte, c chan int, m map[int]int, f func())
-func argstring(x, y string)
-func argslice(x, y []string)
-func argiface(x interface{}, y interface {
- m()
-})
-func argcomplex(x complex64, y complex128)
-func argstruct(x S, y struct{})
-func argarray(x [2]S)
-func returnint() int
-func returnbyte(x int) byte
-func returnnamed(x byte) (r1 int, r2 int16, r3 string, r4 byte)
-func returnintmissing() int
-func leaf(x, y int) int
-
-func noprof(x int)
-func dupok(x int)
-func nosplit(x int)
-func rodata(x int)
-func noptr(x int)
-func wrapper(x int)
-
-func f15271() (x uint32)
-func f17584(x float32, y complex64)
-
-func noframe1(x int32)
-func noframe2(x int32)
diff --git a/libgo/go/cmd/vet/testdata/asm/asm1.s b/libgo/go/cmd/vet/testdata/asm/asm1.s
deleted file mode 100644
index cac6ed22cd0..00000000000
--- a/libgo/go/cmd/vet/testdata/asm/asm1.s
+++ /dev/null
@@ -1,315 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build amd64
-// +build vet_test
-
-TEXT ·arg1(SB),0,$0-2
- MOVB x+0(FP), AX
- // MOVB x+0(FP), AX // commented out instructions used to panic
- MOVB y+1(FP), BX
- MOVW x+0(FP), AX // ERROR "\[amd64\] arg1: invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
- MOVW y+1(FP), AX // ERROR "invalid MOVW of y\+1\(FP\); uint8 is 1-byte value"
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int8 is 1-byte value"
- MOVL y+1(FP), AX // ERROR "invalid MOVL of y\+1\(FP\); uint8 is 1-byte value"
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int8 is 1-byte value"
- MOVQ y+1(FP), AX // ERROR "invalid MOVQ of y\+1\(FP\); uint8 is 1-byte value"
- MOVB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
- MOVB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
- TESTB x+0(FP), AX
- TESTB y+1(FP), BX
- TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int8 is 1-byte value"
- TESTW y+1(FP), AX // ERROR "invalid TESTW of y\+1\(FP\); uint8 is 1-byte value"
- TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int8 is 1-byte value"
- TESTL y+1(FP), AX // ERROR "invalid TESTL of y\+1\(FP\); uint8 is 1-byte value"
- TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int8 is 1-byte value"
- TESTQ y+1(FP), AX // ERROR "invalid TESTQ of y\+1\(FP\); uint8 is 1-byte value"
- TESTB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
- TESTB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
- MOVB 8(SP), AX // ERROR "8\(SP\) should be x\+0\(FP\)"
- MOVB 9(SP), AX // ERROR "9\(SP\) should be y\+1\(FP\)"
- MOVB 10(SP), AX // ERROR "use of 10\(SP\) points beyond argument frame"
- RET
-
-TEXT ·arg2(SB),0,$0-4
- MOVB x+0(FP), AX // ERROR "arg2: invalid MOVB of x\+0\(FP\); int16 is 2-byte value"
- MOVB y+2(FP), AX // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
- MOVW x+0(FP), AX
- MOVW y+2(FP), BX
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int16 is 2-byte value"
- MOVL y+2(FP), AX // ERROR "invalid MOVL of y\+2\(FP\); uint16 is 2-byte value"
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int16 is 2-byte value"
- MOVQ y+2(FP), AX // ERROR "invalid MOVQ of y\+2\(FP\); uint16 is 2-byte value"
- MOVW x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
- MOVW y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
- TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int16 is 2-byte value"
- TESTB y+2(FP), AX // ERROR "invalid TESTB of y\+2\(FP\); uint16 is 2-byte value"
- TESTW x+0(FP), AX
- TESTW y+2(FP), BX
- TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int16 is 2-byte value"
- TESTL y+2(FP), AX // ERROR "invalid TESTL of y\+2\(FP\); uint16 is 2-byte value"
- TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int16 is 2-byte value"
- TESTQ y+2(FP), AX // ERROR "invalid TESTQ of y\+2\(FP\); uint16 is 2-byte value"
- TESTW x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
- TESTW y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
- RET
-
-TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
- MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int32 is 4-byte value"
- MOVW y+4(FP), AX // ERROR "invalid MOVW of y\+4\(FP\); uint32 is 4-byte value"
- MOVL x+0(FP), AX
- MOVL y+4(FP), AX
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int32 is 4-byte value"
- MOVQ y+4(FP), AX // ERROR "invalid MOVQ of y\+4\(FP\); uint32 is 4-byte value"
- MOVL x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVL y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int32 is 4-byte value"
- TESTB y+4(FP), BX // ERROR "invalid TESTB of y\+4\(FP\); uint32 is 4-byte value"
- TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int32 is 4-byte value"
- TESTW y+4(FP), AX // ERROR "invalid TESTW of y\+4\(FP\); uint32 is 4-byte value"
- TESTL x+0(FP), AX
- TESTL y+4(FP), AX
- TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int32 is 4-byte value"
- TESTQ y+4(FP), AX // ERROR "invalid TESTQ of y\+4\(FP\); uint32 is 4-byte value"
- TESTL x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- TESTL y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- RET
-
-TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
- MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value"
- MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value"
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int64 is 8-byte value"
- MOVL y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); uint64 is 8-byte value"
- MOVQ x+0(FP), AX
- MOVQ y+8(FP), AX
- MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int64 is 8-byte value"
- TESTB y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); uint64 is 8-byte value"
- TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int64 is 8-byte value"
- TESTW y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); uint64 is 8-byte value"
- TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int64 is 8-byte value"
- TESTL y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); uint64 is 8-byte value"
- TESTQ x+0(FP), AX
- TESTQ y+8(FP), AX
- TESTQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- RET
-
-TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int is 8-byte value"
- MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint is 8-byte value"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int is 8-byte value"
- MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint is 8-byte value"
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int is 8-byte value"
- MOVL y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); uint is 8-byte value"
- MOVQ x+0(FP), AX
- MOVQ y+8(FP), AX
- MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int is 8-byte value"
- TESTB y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); uint is 8-byte value"
- TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int is 8-byte value"
- TESTW y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); uint is 8-byte value"
- TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int is 8-byte value"
- TESTL y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); uint is 8-byte value"
- TESTQ x+0(FP), AX
- TESTQ y+8(FP), AX
- TESTQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- RET
-
-TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-40"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 8-byte value"
- MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); \*byte is 8-byte value"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); \*byte is 8-byte value"
- MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); \*byte is 8-byte value"
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); \*byte is 8-byte value"
- MOVL y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); \*byte is 8-byte value"
- MOVQ x+0(FP), AX
- MOVQ y+8(FP), AX
- MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); \*byte is 8-byte value"
- TESTB y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); \*byte is 8-byte value"
- TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); \*byte is 8-byte value"
- TESTW y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); \*byte is 8-byte value"
- TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); \*byte is 8-byte value"
- TESTL y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); \*byte is 8-byte value"
- TESTQ x+0(FP), AX
- TESTQ y+8(FP), AX
- TESTQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- MOVL c+16(FP), AX // ERROR "invalid MOVL of c\+16\(FP\); chan int is 8-byte value"
- MOVL m+24(FP), AX // ERROR "invalid MOVL of m\+24\(FP\); map\[int\]int is 8-byte value"
- MOVL f+32(FP), AX // ERROR "invalid MOVL of f\+32\(FP\); func\(\) is 8-byte value"
- RET
-
-TEXT ·argstring(SB),0,$32 // ERROR "wrong argument size 0; expected \$\.\.\.-32"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); string base is 8-byte value"
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); string base is 8-byte value"
- MOVQ x+0(FP), AX
- MOVW x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); string base is 8-byte value"
- MOVL x_base+0(FP), AX // ERROR "invalid MOVL of x_base\+0\(FP\); string base is 8-byte value"
- MOVQ x_base+0(FP), AX
- MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVL x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVW x_len+8(FP), AX // ERROR "invalid MOVW of x_len\+8\(FP\); string len is 8-byte value"
- MOVL x_len+8(FP), AX // ERROR "invalid MOVL of x_len\+8\(FP\); string len is 8-byte value"
- MOVQ x_len+8(FP), AX
- MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+16\(FP\)"
- MOVQ y_len+8(FP), AX // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+24\(FP\)"
- RET
-
-TEXT ·argslice(SB),0,$48 // ERROR "wrong argument size 0; expected \$\.\.\.-48"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); slice base is 8-byte value"
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); slice base is 8-byte value"
- MOVQ x+0(FP), AX
- MOVW x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); slice base is 8-byte value"
- MOVL x_base+0(FP), AX // ERROR "invalid MOVL of x_base\+0\(FP\); slice base is 8-byte value"
- MOVQ x_base+0(FP), AX
- MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVL x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVW x_len+8(FP), AX // ERROR "invalid MOVW of x_len\+8\(FP\); slice len is 8-byte value"
- MOVL x_len+8(FP), AX // ERROR "invalid MOVL of x_len\+8\(FP\); slice len is 8-byte value"
- MOVQ x_len+8(FP), AX
- MOVW x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVL x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVQ x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVW x_cap+16(FP), AX // ERROR "invalid MOVW of x_cap\+16\(FP\); slice cap is 8-byte value"
- MOVL x_cap+16(FP), AX // ERROR "invalid MOVL of x_cap\+16\(FP\); slice cap is 8-byte value"
- MOVQ x_cap+16(FP), AX
- MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+24\(FP\)"
- MOVQ y_len+8(FP), AX // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+32\(FP\)"
- MOVQ y_cap+16(FP), AX // ERROR "invalid offset y_cap\+16\(FP\); expected y_cap\+40\(FP\)"
- RET
-
-TEXT ·argiface(SB),0,$0-32
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); interface type is 8-byte value"
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); interface type is 8-byte value"
- MOVQ x+0(FP), AX
- MOVW x_type+0(FP), AX // ERROR "invalid MOVW of x_type\+0\(FP\); interface type is 8-byte value"
- MOVL x_type+0(FP), AX // ERROR "invalid MOVL of x_type\+0\(FP\); interface type is 8-byte value"
- MOVQ x_type+0(FP), AX
- MOVQ x_itable+0(FP), AX // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
- MOVQ x_itable+1(FP), AX // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
- MOVW x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVL x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVQ x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVW x_data+8(FP), AX // ERROR "invalid MOVW of x_data\+8\(FP\); interface data is 8-byte value"
- MOVL x_data+8(FP), AX // ERROR "invalid MOVL of x_data\+8\(FP\); interface data is 8-byte value"
- MOVQ x_data+8(FP), AX
- MOVW y+16(FP), AX // ERROR "invalid MOVW of y\+16\(FP\); interface itable is 8-byte value"
- MOVL y+16(FP), AX // ERROR "invalid MOVL of y\+16\(FP\); interface itable is 8-byte value"
- MOVQ y+16(FP), AX
- MOVW y_itable+16(FP), AX // ERROR "invalid MOVW of y_itable\+16\(FP\); interface itable is 8-byte value"
- MOVL y_itable+16(FP), AX // ERROR "invalid MOVL of y_itable\+16\(FP\); interface itable is 8-byte value"
- MOVQ y_itable+16(FP), AX
- MOVQ y_type+16(FP), AX // ERROR "unknown variable y_type; offset 16 is y_itable\+16\(FP\)"
- MOVW y_data+16(FP), AX // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVL y_data+16(FP), AX // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVQ y_data+16(FP), AX // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVW y_data+24(FP), AX // ERROR "invalid MOVW of y_data\+24\(FP\); interface data is 8-byte value"
- MOVL y_data+24(FP), AX // ERROR "invalid MOVL of y_data\+24\(FP\); interface data is 8-byte value"
- MOVQ y_data+24(FP), AX
- RET
-
-TEXT ·argcomplex(SB),0,$24 // ERROR "wrong argument size 0; expected \$\.\.\.-24"
- MOVSS x+0(FP), X0 // ERROR "invalid MOVSS of x\+0\(FP\); complex64 is 8-byte value containing x_real\+0\(FP\) and x_imag\+4\(FP\)"
- MOVSD x+0(FP), X0 // ERROR "invalid MOVSD of x\+0\(FP\); complex64 is 8-byte value containing x_real\+0\(FP\) and x_imag\+4\(FP\)"
- MOVSS x_real+0(FP), X0
- MOVSD x_real+0(FP), X0 // ERROR "invalid MOVSD of x_real\+0\(FP\); real\(complex64\) is 4-byte value"
- MOVSS x_real+4(FP), X0 // ERROR "invalid offset x_real\+4\(FP\); expected x_real\+0\(FP\)"
- MOVSS x_imag+4(FP), X0
- MOVSD x_imag+4(FP), X0 // ERROR "invalid MOVSD of x_imag\+4\(FP\); imag\(complex64\) is 4-byte value"
- MOVSS x_imag+8(FP), X0 // ERROR "invalid offset x_imag\+8\(FP\); expected x_imag\+4\(FP\)"
- MOVSD y+8(FP), X0 // ERROR "invalid MOVSD of y\+8\(FP\); complex128 is 16-byte value containing y_real\+8\(FP\) and y_imag\+16\(FP\)"
- MOVSS y_real+8(FP), X0 // ERROR "invalid MOVSS of y_real\+8\(FP\); real\(complex128\) is 8-byte value"
- MOVSD y_real+8(FP), X0
- MOVSS y_real+16(FP), X0 // ERROR "invalid offset y_real\+16\(FP\); expected y_real\+8\(FP\)"
- MOVSS y_imag+16(FP), X0 // ERROR "invalid MOVSS of y_imag\+16\(FP\); imag\(complex128\) is 8-byte value"
- MOVSD y_imag+16(FP), X0
- MOVSS y_imag+24(FP), X0 // ERROR "invalid offset y_imag\+24\(FP\); expected y_imag\+16\(FP\)"
- RET
-
-TEXT ·argstruct(SB),0,$64 // ERROR "wrong argument size 0; expected \$\.\.\.-24"
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); testdata.S is 24-byte value"
- MOVQ x_i+0(FP), AX // ERROR "invalid MOVQ of x_i\+0\(FP\); int32 is 4-byte value"
- MOVQ x_b+0(FP), AX // ERROR "invalid offset x_b\+0\(FP\); expected x_b\+4\(FP\)"
- MOVQ x_s+8(FP), AX
- MOVQ x_s_base+8(FP), AX
- MOVQ x_s+16(FP), AX // ERROR "invalid offset x_s\+16\(FP\); expected x_s\+8\(FP\), x_s_base\+8\(FP\), or x_s_len\+16\(FP\)"
- MOVQ x_s_len+16(FP), AX
- RET
-
-TEXT ·argarray(SB),0,$64 // ERROR "wrong argument size 0; expected \$\.\.\.-48"
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); \[2\]testdata.S is 48-byte value"
- MOVQ x_0_i+0(FP), AX // ERROR "invalid MOVQ of x_0_i\+0\(FP\); int32 is 4-byte value"
- MOVQ x_0_b+0(FP), AX // ERROR "invalid offset x_0_b\+0\(FP\); expected x_0_b\+4\(FP\)"
- MOVQ x_0_s+8(FP), AX
- MOVQ x_0_s_base+8(FP), AX
- MOVQ x_0_s+16(FP), AX // ERROR "invalid offset x_0_s\+16\(FP\); expected x_0_s\+8\(FP\), x_0_s_base\+8\(FP\), or x_0_s_len\+16\(FP\)"
- MOVQ x_0_s_len+16(FP), AX
- MOVB foo+25(FP), AX // ERROR "unknown variable foo; offset 25 is x_1_i\+24\(FP\)"
- MOVQ x_1_s+32(FP), AX
- MOVQ x_1_s_base+32(FP), AX
- MOVQ x_1_s+40(FP), AX // ERROR "invalid offset x_1_s\+40\(FP\); expected x_1_s\+32\(FP\), x_1_s_base\+32\(FP\), or x_1_s_len\+40\(FP\)"
- MOVQ x_1_s_len+40(FP), AX
- RET
-
-TEXT ·returnint(SB),0,$0-8
- MOVB AX, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 8-byte value"
- MOVW AX, ret+0(FP) // ERROR "invalid MOVW of ret\+0\(FP\); int is 8-byte value"
- MOVL AX, ret+0(FP) // ERROR "invalid MOVL of ret\+0\(FP\); int is 8-byte value"
- MOVQ AX, ret+0(FP)
- MOVQ AX, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)"
- MOVQ AX, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)"
- RET
-
-TEXT ·returnbyte(SB),0,$0-9
- MOVQ x+0(FP), AX
- MOVB AX, ret+8(FP)
- MOVW AX, ret+8(FP) // ERROR "invalid MOVW of ret\+8\(FP\); byte is 1-byte value"
- MOVL AX, ret+8(FP) // ERROR "invalid MOVL of ret\+8\(FP\); byte is 1-byte value"
- MOVQ AX, ret+8(FP) // ERROR "invalid MOVQ of ret\+8\(FP\); byte is 1-byte value"
- MOVB AX, ret+7(FP) // ERROR "invalid offset ret\+7\(FP\); expected ret\+8\(FP\)"
- RET
-
-TEXT ·returnnamed(SB),0,$0-41
- MOVB x+0(FP), AX
- MOVQ AX, r1+8(FP)
- MOVW AX, r2+16(FP)
- MOVQ AX, r3+24(FP)
- MOVQ AX, r3_base+24(FP)
- MOVQ AX, r3_len+32(FP)
- MOVB AX, r4+40(FP)
- MOVL AX, r1+8(FP) // ERROR "invalid MOVL of r1\+8\(FP\); int is 8-byte value"
- RET
-
-TEXT ·returnintmissing(SB),0,$0-8
- RET // ERROR "RET without writing to 8-byte ret\+0\(FP\)"
-
-
-// issue 15271
-TEXT ·f15271(SB), NOSPLIT, $0-4
- // Stick 123 into the low 32 bits of X0.
- MOVQ $123, AX
- PINSRD $0, AX, X0
-
- // Return them.
- PEXTRD $0, X0, x+0(FP)
- RET
-
-// issue 17584
-TEXT ·f17584(SB), NOSPLIT, $12
- MOVSS x+0(FP), X0
- MOVSS y_real+4(FP), X0
- MOVSS y_imag+8(FP), X0
- RET
diff --git a/libgo/go/cmd/vet/testdata/asm/asm2.s b/libgo/go/cmd/vet/testdata/asm/asm2.s
deleted file mode 100644
index c33c02a70b2..00000000000
--- a/libgo/go/cmd/vet/testdata/asm/asm2.s
+++ /dev/null
@@ -1,257 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build 386
-// +build vet_test
-
-TEXT ·arg1(SB),0,$0-2
- MOVB x+0(FP), AX
- MOVB y+1(FP), BX
- MOVW x+0(FP), AX // ERROR "\[386\] arg1: invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
- MOVW y+1(FP), AX // ERROR "invalid MOVW of y\+1\(FP\); uint8 is 1-byte value"
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int8 is 1-byte value"
- MOVL y+1(FP), AX // ERROR "invalid MOVL of y\+1\(FP\); uint8 is 1-byte value"
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int8 is 1-byte value"
- MOVQ y+1(FP), AX // ERROR "invalid MOVQ of y\+1\(FP\); uint8 is 1-byte value"
- MOVB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
- MOVB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
- TESTB x+0(FP), AX
- TESTB y+1(FP), BX
- TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int8 is 1-byte value"
- TESTW y+1(FP), AX // ERROR "invalid TESTW of y\+1\(FP\); uint8 is 1-byte value"
- TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int8 is 1-byte value"
- TESTL y+1(FP), AX // ERROR "invalid TESTL of y\+1\(FP\); uint8 is 1-byte value"
- TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int8 is 1-byte value"
- TESTQ y+1(FP), AX // ERROR "invalid TESTQ of y\+1\(FP\); uint8 is 1-byte value"
- TESTB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
- TESTB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
- MOVB 4(SP), AX // ERROR "4\(SP\) should be x\+0\(FP\)"
- MOVB 5(SP), AX // ERROR "5\(SP\) should be y\+1\(FP\)"
- MOVB 6(SP), AX // ERROR "use of 6\(SP\) points beyond argument frame"
- RET
-
-TEXT ·arg2(SB),0,$0-4
- MOVB x+0(FP), AX // ERROR "arg2: invalid MOVB of x\+0\(FP\); int16 is 2-byte value"
- MOVB y+2(FP), AX // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
- MOVW x+0(FP), AX
- MOVW y+2(FP), BX
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int16 is 2-byte value"
- MOVL y+2(FP), AX // ERROR "invalid MOVL of y\+2\(FP\); uint16 is 2-byte value"
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int16 is 2-byte value"
- MOVQ y+2(FP), AX // ERROR "invalid MOVQ of y\+2\(FP\); uint16 is 2-byte value"
- MOVW x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
- MOVW y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
- TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int16 is 2-byte value"
- TESTB y+2(FP), AX // ERROR "invalid TESTB of y\+2\(FP\); uint16 is 2-byte value"
- TESTW x+0(FP), AX
- TESTW y+2(FP), BX
- TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int16 is 2-byte value"
- TESTL y+2(FP), AX // ERROR "invalid TESTL of y\+2\(FP\); uint16 is 2-byte value"
- TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int16 is 2-byte value"
- TESTQ y+2(FP), AX // ERROR "invalid TESTQ of y\+2\(FP\); uint16 is 2-byte value"
- TESTW x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
- TESTW y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
- RET
-
-TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
- MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int32 is 4-byte value"
- MOVW y+4(FP), AX // ERROR "invalid MOVW of y\+4\(FP\); uint32 is 4-byte value"
- MOVL x+0(FP), AX
- MOVL y+4(FP), AX
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int32 is 4-byte value"
- MOVQ y+4(FP), AX // ERROR "invalid MOVQ of y\+4\(FP\); uint32 is 4-byte value"
- MOVL x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVL y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int32 is 4-byte value"
- TESTB y+4(FP), BX // ERROR "invalid TESTB of y\+4\(FP\); uint32 is 4-byte value"
- TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int32 is 4-byte value"
- TESTW y+4(FP), AX // ERROR "invalid TESTW of y\+4\(FP\); uint32 is 4-byte value"
- TESTL x+0(FP), AX
- TESTL y+4(FP), AX
- TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int32 is 4-byte value"
- TESTQ y+4(FP), AX // ERROR "invalid TESTQ of y\+4\(FP\); uint32 is 4-byte value"
- TESTL x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- TESTL y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- RET
-
-TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
- MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value"
- MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value"
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int64 is 8-byte value containing x_lo\+0\(FP\) and x_hi\+4\(FP\)"
- MOVL x_lo+0(FP), AX
- MOVL x_hi+4(FP), AX
- MOVL y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); uint64 is 8-byte value containing y_lo\+8\(FP\) and y_hi\+12\(FP\)"
- MOVL y_lo+8(FP), AX
- MOVL y_hi+12(FP), AX
- MOVQ x+0(FP), AX
- MOVQ y+8(FP), AX
- MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int64 is 8-byte value"
- TESTB y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); uint64 is 8-byte value"
- TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int64 is 8-byte value"
- TESTW y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); uint64 is 8-byte value"
- TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int64 is 8-byte value containing x_lo\+0\(FP\) and x_hi\+4\(FP\)"
- TESTL y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); uint64 is 8-byte value containing y_lo\+8\(FP\) and y_hi\+12\(FP\)"
- TESTQ x+0(FP), AX
- TESTQ y+8(FP), AX
- TESTQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- RET
-
-TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-8"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int is 4-byte value"
- MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint is 4-byte value"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int is 4-byte value"
- MOVW y+4(FP), AX // ERROR "invalid MOVW of y\+4\(FP\); uint is 4-byte value"
- MOVL x+0(FP), AX
- MOVL y+4(FP), AX
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int is 4-byte value"
- MOVQ y+4(FP), AX // ERROR "invalid MOVQ of y\+4\(FP\); uint is 4-byte value"
- MOVQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int is 4-byte value"
- TESTB y+4(FP), BX // ERROR "invalid TESTB of y\+4\(FP\); uint is 4-byte value"
- TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int is 4-byte value"
- TESTW y+4(FP), AX // ERROR "invalid TESTW of y\+4\(FP\); uint is 4-byte value"
- TESTL x+0(FP), AX
- TESTL y+4(FP), AX
- TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int is 4-byte value"
- TESTQ y+4(FP), AX // ERROR "invalid TESTQ of y\+4\(FP\); uint is 4-byte value"
- TESTQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- RET
-
-TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-20"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 4-byte value"
- MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); \*byte is 4-byte value"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); \*byte is 4-byte value"
- MOVW y+4(FP), AX // ERROR "invalid MOVW of y\+4\(FP\); \*byte is 4-byte value"
- MOVL x+0(FP), AX
- MOVL y+4(FP), AX
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); \*byte is 4-byte value"
- MOVQ y+4(FP), AX // ERROR "invalid MOVQ of y\+4\(FP\); \*byte is 4-byte value"
- MOVQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); \*byte is 4-byte value"
- TESTB y+4(FP), BX // ERROR "invalid TESTB of y\+4\(FP\); \*byte is 4-byte value"
- TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); \*byte is 4-byte value"
- TESTW y+4(FP), AX // ERROR "invalid TESTW of y\+4\(FP\); \*byte is 4-byte value"
- TESTL x+0(FP), AX
- TESTL y+4(FP), AX
- TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); \*byte is 4-byte value"
- TESTQ y+4(FP), AX // ERROR "invalid TESTQ of y\+4\(FP\); \*byte is 4-byte value"
- TESTQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- MOVW c+8(FP), AX // ERROR "invalid MOVW of c\+8\(FP\); chan int is 4-byte value"
- MOVW m+12(FP), AX // ERROR "invalid MOVW of m\+12\(FP\); map\[int\]int is 4-byte value"
- MOVW f+16(FP), AX // ERROR "invalid MOVW of f\+16\(FP\); func\(\) is 4-byte value"
- RET
-
-TEXT ·argstring(SB),0,$16 // ERROR "wrong argument size 0; expected \$\.\.\.-16"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); string base is 4-byte value"
- MOVL x+0(FP), AX
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); string base is 4-byte value"
- MOVW x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); string base is 4-byte value"
- MOVL x_base+0(FP), AX
- MOVQ x_base+0(FP), AX // ERROR "invalid MOVQ of x_base\+0\(FP\); string base is 4-byte value"
- MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVL x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVW x_len+4(FP), AX // ERROR "invalid MOVW of x_len\+4\(FP\); string len is 4-byte value"
- MOVL x_len+4(FP), AX
- MOVQ x_len+4(FP), AX // ERROR "invalid MOVQ of x_len\+4\(FP\); string len is 4-byte value"
- MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+8\(FP\)"
- MOVQ y_len+4(FP), AX // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+12\(FP\)"
- RET
-
-TEXT ·argslice(SB),0,$24 // ERROR "wrong argument size 0; expected \$\.\.\.-24"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); slice base is 4-byte value"
- MOVL x+0(FP), AX
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); slice base is 4-byte value"
- MOVW x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); slice base is 4-byte value"
- MOVL x_base+0(FP), AX
- MOVQ x_base+0(FP), AX // ERROR "invalid MOVQ of x_base\+0\(FP\); slice base is 4-byte value"
- MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVL x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVW x_len+4(FP), AX // ERROR "invalid MOVW of x_len\+4\(FP\); slice len is 4-byte value"
- MOVL x_len+4(FP), AX
- MOVQ x_len+4(FP), AX // ERROR "invalid MOVQ of x_len\+4\(FP\); slice len is 4-byte value"
- MOVW x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
- MOVL x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
- MOVQ x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
- MOVW x_cap+8(FP), AX // ERROR "invalid MOVW of x_cap\+8\(FP\); slice cap is 4-byte value"
- MOVL x_cap+8(FP), AX
- MOVQ x_cap+8(FP), AX // ERROR "invalid MOVQ of x_cap\+8\(FP\); slice cap is 4-byte value"
- MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+12\(FP\)"
- MOVQ y_len+4(FP), AX // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+16\(FP\)"
- MOVQ y_cap+8(FP), AX // ERROR "invalid offset y_cap\+8\(FP\); expected y_cap\+20\(FP\)"
- RET
-
-TEXT ·argiface(SB),0,$0-16
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); interface type is 4-byte value"
- MOVL x+0(FP), AX
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); interface type is 4-byte value"
- MOVW x_type+0(FP), AX // ERROR "invalid MOVW of x_type\+0\(FP\); interface type is 4-byte value"
- MOVL x_type+0(FP), AX
- MOVQ x_type+0(FP), AX // ERROR "invalid MOVQ of x_type\+0\(FP\); interface type is 4-byte value"
- MOVQ x_itable+0(FP), AX // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
- MOVQ x_itable+1(FP), AX // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
- MOVW x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
- MOVL x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
- MOVQ x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
- MOVW x_data+4(FP), AX // ERROR "invalid MOVW of x_data\+4\(FP\); interface data is 4-byte value"
- MOVL x_data+4(FP), AX
- MOVQ x_data+4(FP), AX // ERROR "invalid MOVQ of x_data\+4\(FP\); interface data is 4-byte value"
- MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); interface itable is 4-byte value"
- MOVL y+8(FP), AX
- MOVQ y+8(FP), AX // ERROR "invalid MOVQ of y\+8\(FP\); interface itable is 4-byte value"
- MOVW y_itable+8(FP), AX // ERROR "invalid MOVW of y_itable\+8\(FP\); interface itable is 4-byte value"
- MOVL y_itable+8(FP), AX
- MOVQ y_itable+8(FP), AX // ERROR "invalid MOVQ of y_itable\+8\(FP\); interface itable is 4-byte value"
- MOVQ y_type+8(FP), AX // ERROR "unknown variable y_type; offset 8 is y_itable\+8\(FP\)"
- MOVW y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
- MOVL y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
- MOVQ y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
- MOVW y_data+12(FP), AX // ERROR "invalid MOVW of y_data\+12\(FP\); interface data is 4-byte value"
- MOVL y_data+12(FP), AX
- MOVQ y_data+12(FP), AX // ERROR "invalid MOVQ of y_data\+12\(FP\); interface data is 4-byte value"
- RET
-
-TEXT ·returnint(SB),0,$0-4
- MOVB AX, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 4-byte value"
- MOVW AX, ret+0(FP) // ERROR "invalid MOVW of ret\+0\(FP\); int is 4-byte value"
- MOVL AX, ret+0(FP)
- MOVQ AX, ret+0(FP) // ERROR "invalid MOVQ of ret\+0\(FP\); int is 4-byte value"
- MOVQ AX, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)"
- MOVQ AX, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)"
- RET
-
-TEXT ·returnbyte(SB),0,$0-5
- MOVL x+0(FP), AX
- MOVB AX, ret+4(FP)
- MOVW AX, ret+4(FP) // ERROR "invalid MOVW of ret\+4\(FP\); byte is 1-byte value"
- MOVL AX, ret+4(FP) // ERROR "invalid MOVL of ret\+4\(FP\); byte is 1-byte value"
- MOVQ AX, ret+4(FP) // ERROR "invalid MOVQ of ret\+4\(FP\); byte is 1-byte value"
- MOVB AX, ret+3(FP) // ERROR "invalid offset ret\+3\(FP\); expected ret\+4\(FP\)"
- RET
-
-TEXT ·returnnamed(SB),0,$0-21
- MOVB x+0(FP), AX
- MOVL AX, r1+4(FP)
- MOVW AX, r2+8(FP)
- MOVL AX, r3+12(FP)
- MOVL AX, r3_base+12(FP)
- MOVL AX, r3_len+16(FP)
- MOVB AX, r4+20(FP)
- MOVQ AX, r1+4(FP) // ERROR "invalid MOVQ of r1\+4\(FP\); int is 4-byte value"
- RET
-
-TEXT ·returnintmissing(SB),0,$0-4
- RET // ERROR "RET without writing to 4-byte ret\+0\(FP\)"
diff --git a/libgo/go/cmd/vet/testdata/asm/asm3.s b/libgo/go/cmd/vet/testdata/asm/asm3.s
deleted file mode 100644
index 83e53862d7d..00000000000
--- a/libgo/go/cmd/vet/testdata/asm/asm3.s
+++ /dev/null
@@ -1,192 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build arm
-// +build vet_test
-
-TEXT ·arg1(SB),0,$0-2
- MOVB x+0(FP), AX
- MOVB y+1(FP), BX
- MOVH x+0(FP), AX // ERROR "\[arm\] arg1: invalid MOVH of x\+0\(FP\); int8 is 1-byte value"
- MOVH y+1(FP), AX // ERROR "invalid MOVH of y\+1\(FP\); uint8 is 1-byte value"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
- MOVW y+1(FP), AX // ERROR "invalid MOVW of y\+1\(FP\); uint8 is 1-byte value"
- MOVB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
- MOVB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
- MOVB 8(R13), AX // ERROR "8\(R13\) should be x\+0\(FP\)"
- MOVB 9(R13), AX // ERROR "9\(R13\) should be y\+1\(FP\)"
- MOVB 10(R13), AX // ERROR "use of 10\(R13\) points beyond argument frame"
- RET
-
-TEXT ·arg2(SB),0,$0-4
- MOVB x+0(FP), AX // ERROR "arg2: invalid MOVB of x\+0\(FP\); int16 is 2-byte value"
- MOVB y+2(FP), AX // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
- MOVH x+0(FP), AX
- MOVH y+2(FP), BX
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int16 is 2-byte value"
- MOVW y+2(FP), AX // ERROR "invalid MOVW of y\+2\(FP\); uint16 is 2-byte value"
- MOVH x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
- MOVH y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
- RET
-
-TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
- MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
- MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); int32 is 4-byte value"
- MOVH y+4(FP), AX // ERROR "invalid MOVH of y\+4\(FP\); uint32 is 4-byte value"
- MOVW x+0(FP), AX
- MOVW y+4(FP), AX
- MOVW x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVW y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- RET
-
-TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
- MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
- MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); int64 is 8-byte value"
- MOVH y+8(FP), AX // ERROR "invalid MOVH of y\+8\(FP\); uint64 is 8-byte value"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value containing x_lo\+0\(FP\) and x_hi\+4\(FP\)"
- MOVW x_lo+0(FP), AX
- MOVW x_hi+4(FP), AX
- MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value containing y_lo\+8\(FP\) and y_hi\+12\(FP\)"
- MOVW y_lo+8(FP), AX
- MOVW y_hi+12(FP), AX
- MOVQ x+0(FP), AX
- MOVQ y+8(FP), AX
- MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- RET
-
-TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-8"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int is 4-byte value"
- MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint is 4-byte value"
- MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); int is 4-byte value"
- MOVH y+4(FP), AX // ERROR "invalid MOVH of y\+4\(FP\); uint is 4-byte value"
- MOVW x+0(FP), AX
- MOVW y+4(FP), AX
- MOVQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- RET
-
-TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-20"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 4-byte value"
- MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); \*byte is 4-byte value"
- MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); \*byte is 4-byte value"
- MOVH y+4(FP), AX // ERROR "invalid MOVH of y\+4\(FP\); \*byte is 4-byte value"
- MOVW x+0(FP), AX
- MOVW y+4(FP), AX
- MOVQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- MOVH c+8(FP), AX // ERROR "invalid MOVH of c\+8\(FP\); chan int is 4-byte value"
- MOVH m+12(FP), AX // ERROR "invalid MOVH of m\+12\(FP\); map\[int\]int is 4-byte value"
- MOVH f+16(FP), AX // ERROR "invalid MOVH of f\+16\(FP\); func\(\) is 4-byte value"
- RET
-
-TEXT ·argstring(SB),0,$16 // ERROR "wrong argument size 0; expected \$\.\.\.-16"
- MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); string base is 4-byte value"
- MOVW x+0(FP), AX
- MOVH x_base+0(FP), AX // ERROR "invalid MOVH of x_base\+0\(FP\); string base is 4-byte value"
- MOVW x_base+0(FP), AX
- MOVH x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVH x_len+4(FP), AX // ERROR "invalid MOVH of x_len\+4\(FP\); string len is 4-byte value"
- MOVW x_len+4(FP), AX
- MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+8\(FP\)"
- MOVQ y_len+4(FP), AX // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+12\(FP\)"
- RET
-
-TEXT ·argslice(SB),0,$24 // ERROR "wrong argument size 0; expected \$\.\.\.-24"
- MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); slice base is 4-byte value"
- MOVW x+0(FP), AX
- MOVH x_base+0(FP), AX // ERROR "invalid MOVH of x_base\+0\(FP\); slice base is 4-byte value"
- MOVW x_base+0(FP), AX
- MOVH x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVH x_len+4(FP), AX // ERROR "invalid MOVH of x_len\+4\(FP\); slice len is 4-byte value"
- MOVW x_len+4(FP), AX
- MOVH x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
- MOVW x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
- MOVQ x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
- MOVH x_cap+8(FP), AX // ERROR "invalid MOVH of x_cap\+8\(FP\); slice cap is 4-byte value"
- MOVW x_cap+8(FP), AX
- MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+12\(FP\)"
- MOVQ y_len+4(FP), AX // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+16\(FP\)"
- MOVQ y_cap+8(FP), AX // ERROR "invalid offset y_cap\+8\(FP\); expected y_cap\+20\(FP\)"
- RET
-
-TEXT ·argiface(SB),0,$0-16
- MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); interface type is 4-byte value"
- MOVW x+0(FP), AX
- MOVH x_type+0(FP), AX // ERROR "invalid MOVH of x_type\+0\(FP\); interface type is 4-byte value"
- MOVW x_type+0(FP), AX
- MOVQ x_itable+0(FP), AX // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
- MOVQ x_itable+1(FP), AX // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
- MOVH x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
- MOVW x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
- MOVQ x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
- MOVH x_data+4(FP), AX // ERROR "invalid MOVH of x_data\+4\(FP\); interface data is 4-byte value"
- MOVW x_data+4(FP), AX
- MOVH y+8(FP), AX // ERROR "invalid MOVH of y\+8\(FP\); interface itable is 4-byte value"
- MOVW y+8(FP), AX
- MOVH y_itable+8(FP), AX // ERROR "invalid MOVH of y_itable\+8\(FP\); interface itable is 4-byte value"
- MOVW y_itable+8(FP), AX
- MOVQ y_type+8(FP), AX // ERROR "unknown variable y_type; offset 8 is y_itable\+8\(FP\)"
- MOVH y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
- MOVW y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
- MOVQ y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
- MOVH y_data+12(FP), AX // ERROR "invalid MOVH of y_data\+12\(FP\); interface data is 4-byte value"
- MOVW y_data+12(FP), AX
- RET
-
-TEXT ·returnint(SB),0,$0-4
- MOVB AX, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 4-byte value"
- MOVH AX, ret+0(FP) // ERROR "invalid MOVH of ret\+0\(FP\); int is 4-byte value"
- MOVW AX, ret+0(FP)
- MOVQ AX, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)"
- MOVQ AX, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)"
- RET
-
-TEXT ·returnbyte(SB),0,$0-5
- MOVW x+0(FP), AX
- MOVB AX, ret+4(FP)
- MOVH AX, ret+4(FP) // ERROR "invalid MOVH of ret\+4\(FP\); byte is 1-byte value"
- MOVW AX, ret+4(FP) // ERROR "invalid MOVW of ret\+4\(FP\); byte is 1-byte value"
- MOVB AX, ret+3(FP) // ERROR "invalid offset ret\+3\(FP\); expected ret\+4\(FP\)"
- RET
-
-TEXT ·returnnamed(SB),0,$0-21
- MOVB x+0(FP), AX
- MOVW AX, r1+4(FP)
- MOVH AX, r2+8(FP)
- MOVW AX, r3+12(FP)
- MOVW AX, r3_base+12(FP)
- MOVW AX, r3_len+16(FP)
- MOVB AX, r4+20(FP)
- MOVB AX, r1+4(FP) // ERROR "invalid MOVB of r1\+4\(FP\); int is 4-byte value"
- RET
-
-TEXT ·returnintmissing(SB),0,$0-4
- RET // ERROR "RET without writing to 4-byte ret\+0\(FP\)"
-
-TEXT ·leaf(SB),0,$-4-12
- MOVW x+0(FP), AX
- MOVW y+4(FP), AX
- MOVW AX, ret+8(FP)
- RET
-
-TEXT ·noframe1(SB),0,$0-4
- MOVW 0(R13), AX // Okay; our saved LR
- MOVW 4(R13), AX // Okay; caller's saved LR
- MOVW x+8(R13), AX // Okay; x argument
- MOVW 12(R13), AX // ERROR "use of 12\(R13\) points beyond argument frame"
- RET
-
-TEXT ·noframe2(SB),NOFRAME,$0-4
- MOVW 0(R13), AX // Okay; caller's saved LR
- MOVW x+4(R13), AX // Okay; x argument
- MOVW 8(R13), AX // ERROR "use of 8\(R13\) points beyond argument frame"
- MOVW 12(R13), AX // ERROR "use of 12\(R13\) points beyond argument frame"
- RET
diff --git a/libgo/go/cmd/vet/testdata/asm/asm4.s b/libgo/go/cmd/vet/testdata/asm/asm4.s
deleted file mode 100644
index 044b050b6b9..00000000000
--- a/libgo/go/cmd/vet/testdata/asm/asm4.s
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build amd64
-// +build vet_test
-
-// Test cases for symbolic NOSPLIT etc. on TEXT symbols.
-
-TEXT ·noprof(SB),NOPROF,$0-8
- RET
-
-TEXT ·dupok(SB),DUPOK,$0-8
- RET
-
-TEXT ·nosplit(SB),NOSPLIT,$0
- RET
-
-TEXT ·rodata(SB),RODATA,$0-8
- RET
-
-TEXT ·noptr(SB),NOPTR|NOSPLIT,$0
- RET
-
-TEXT ·wrapper(SB),WRAPPER,$0-8
- RET
diff --git a/libgo/go/cmd/vet/testdata/asm/asm5.s b/libgo/go/cmd/vet/testdata/asm/asm5.s
deleted file mode 100644
index c6176e9669f..00000000000
--- a/libgo/go/cmd/vet/testdata/asm/asm5.s
+++ /dev/null
@@ -1,193 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build mips64
-// +build vet_test
-
-TEXT ·arg1(SB),0,$0-2
- MOVB x+0(FP), R1
- MOVBU y+1(FP), R2
- MOVH x+0(FP), R1 // ERROR "\[mips64\] arg1: invalid MOVH of x\+0\(FP\); int8 is 1-byte value"
- MOVHU y+1(FP), R1 // ERROR "invalid MOVHU of y\+1\(FP\); uint8 is 1-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
- MOVWU y+1(FP), R1 // ERROR "invalid MOVWU of y\+1\(FP\); uint8 is 1-byte value"
- MOVV x+0(FP), R1 // ERROR "invalid MOVV of x\+0\(FP\); int8 is 1-byte value"
- MOVV y+1(FP), R1 // ERROR "invalid MOVV of y\+1\(FP\); uint8 is 1-byte value"
- MOVB x+1(FP), R1 // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
- MOVBU y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
- MOVB 16(R29), R1 // ERROR "16\(R29\) should be x\+0\(FP\)"
- MOVB 17(R29), R1 // ERROR "17\(R29\) should be y\+1\(FP\)"
- MOVB 18(R29), R1 // ERROR "use of 18\(R29\) points beyond argument frame"
- RET
-
-TEXT ·arg2(SB),0,$0-4
- MOVBU x+0(FP), R1 // ERROR "arg2: invalid MOVBU of x\+0\(FP\); int16 is 2-byte value"
- MOVB y+2(FP), R1 // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
- MOVHU x+0(FP), R1
- MOVH y+2(FP), R2
- MOVWU x+0(FP), R1 // ERROR "invalid MOVWU of x\+0\(FP\); int16 is 2-byte value"
- MOVW y+2(FP), R1 // ERROR "invalid MOVW of y\+2\(FP\); uint16 is 2-byte value"
- MOVV x+0(FP), R1 // ERROR "invalid MOVV of x\+0\(FP\); int16 is 2-byte value"
- MOVV y+2(FP), R1 // ERROR "invalid MOVV of y\+2\(FP\); uint16 is 2-byte value"
- MOVHU x+2(FP), R1 // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
- MOVH y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
- RET
-
-TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8"
- MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
- MOVB y+4(FP), R2 // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int32 is 4-byte value"
- MOVH y+4(FP), R1 // ERROR "invalid MOVH of y\+4\(FP\); uint32 is 4-byte value"
- MOVW x+0(FP), R1
- MOVW y+4(FP), R1
- MOVV x+0(FP), R1 // ERROR "invalid MOVV of x\+0\(FP\); int32 is 4-byte value"
- MOVV y+4(FP), R1 // ERROR "invalid MOVV of y\+4\(FP\); uint32 is 4-byte value"
- MOVW x+4(FP), R1 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVW y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- RET
-
-TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
- MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
- MOVB y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int64 is 8-byte value"
- MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); uint64 is 8-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value"
- MOVW y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value"
- MOVV x+0(FP), R1
- MOVV y+8(FP), R1
- MOVV x+8(FP), R1 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVV y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- RET
-
-TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
- MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int is 8-byte value"
- MOVB y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); uint is 8-byte value"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int is 8-byte value"
- MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); uint is 8-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int is 8-byte value"
- MOVW y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); uint is 8-byte value"
- MOVV x+0(FP), R1
- MOVV y+8(FP), R1
- MOVV x+8(FP), R1 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVV y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- RET
-
-TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-40"
- MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 8-byte value"
- MOVB y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); \*byte is 8-byte value"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); \*byte is 8-byte value"
- MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); \*byte is 8-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); \*byte is 8-byte value"
- MOVW y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); \*byte is 8-byte value"
- MOVV x+0(FP), R1
- MOVV y+8(FP), R1
- MOVV x+8(FP), R1 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVV y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- MOVW c+16(FP), R1 // ERROR "invalid MOVW of c\+16\(FP\); chan int is 8-byte value"
- MOVW m+24(FP), R1 // ERROR "invalid MOVW of m\+24\(FP\); map\[int\]int is 8-byte value"
- MOVW f+32(FP), R1 // ERROR "invalid MOVW of f\+32\(FP\); func\(\) is 8-byte value"
- RET
-
-TEXT ·argstring(SB),0,$32 // ERROR "wrong argument size 0; expected \$\.\.\.-32"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); string base is 8-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); string base is 8-byte value"
- MOVV x+0(FP), R1
- MOVH x_base+0(FP), R1 // ERROR "invalid MOVH of x_base\+0\(FP\); string base is 8-byte value"
- MOVW x_base+0(FP), R1 // ERROR "invalid MOVW of x_base\+0\(FP\); string base is 8-byte value"
- MOVV x_base+0(FP), R1
- MOVH x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVW x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVV x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVH x_len+8(FP), R1 // ERROR "invalid MOVH of x_len\+8\(FP\); string len is 8-byte value"
- MOVW x_len+8(FP), R1 // ERROR "invalid MOVW of x_len\+8\(FP\); string len is 8-byte value"
- MOVV x_len+8(FP), R1
- MOVV y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+16\(FP\)"
- MOVV y_len+8(FP), R1 // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+24\(FP\)"
- RET
-
-TEXT ·argslice(SB),0,$48 // ERROR "wrong argument size 0; expected \$\.\.\.-48"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); slice base is 8-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); slice base is 8-byte value"
- MOVV x+0(FP), R1
- MOVH x_base+0(FP), R1 // ERROR "invalid MOVH of x_base\+0\(FP\); slice base is 8-byte value"
- MOVW x_base+0(FP), R1 // ERROR "invalid MOVW of x_base\+0\(FP\); slice base is 8-byte value"
- MOVV x_base+0(FP), R1
- MOVH x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVW x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVV x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVH x_len+8(FP), R1 // ERROR "invalid MOVH of x_len\+8\(FP\); slice len is 8-byte value"
- MOVW x_len+8(FP), R1 // ERROR "invalid MOVW of x_len\+8\(FP\); slice len is 8-byte value"
- MOVV x_len+8(FP), R1
- MOVH x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVW x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVV x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVH x_cap+16(FP), R1 // ERROR "invalid MOVH of x_cap\+16\(FP\); slice cap is 8-byte value"
- MOVW x_cap+16(FP), R1 // ERROR "invalid MOVW of x_cap\+16\(FP\); slice cap is 8-byte value"
- MOVV x_cap+16(FP), R1
- MOVV y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+24\(FP\)"
- MOVV y_len+8(FP), R1 // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+32\(FP\)"
- MOVV y_cap+16(FP), R1 // ERROR "invalid offset y_cap\+16\(FP\); expected y_cap\+40\(FP\)"
- RET
-
-TEXT ·argiface(SB),0,$0-32
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); interface type is 8-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); interface type is 8-byte value"
- MOVV x+0(FP), R1
- MOVH x_type+0(FP), R1 // ERROR "invalid MOVH of x_type\+0\(FP\); interface type is 8-byte value"
- MOVW x_type+0(FP), R1 // ERROR "invalid MOVW of x_type\+0\(FP\); interface type is 8-byte value"
- MOVV x_type+0(FP), R1
- MOVV x_itable+0(FP), R1 // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
- MOVV x_itable+1(FP), R1 // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
- MOVH x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVW x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVV x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVH x_data+8(FP), R1 // ERROR "invalid MOVH of x_data\+8\(FP\); interface data is 8-byte value"
- MOVW x_data+8(FP), R1 // ERROR "invalid MOVW of x_data\+8\(FP\); interface data is 8-byte value"
- MOVV x_data+8(FP), R1
- MOVH y+16(FP), R1 // ERROR "invalid MOVH of y\+16\(FP\); interface itable is 8-byte value"
- MOVW y+16(FP), R1 // ERROR "invalid MOVW of y\+16\(FP\); interface itable is 8-byte value"
- MOVV y+16(FP), R1
- MOVH y_itable+16(FP), R1 // ERROR "invalid MOVH of y_itable\+16\(FP\); interface itable is 8-byte value"
- MOVW y_itable+16(FP), R1 // ERROR "invalid MOVW of y_itable\+16\(FP\); interface itable is 8-byte value"
- MOVV y_itable+16(FP), R1
- MOVV y_type+16(FP), R1 // ERROR "unknown variable y_type; offset 16 is y_itable\+16\(FP\)"
- MOVH y_data+16(FP), R1 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVW y_data+16(FP), R1 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVV y_data+16(FP), R1 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVH y_data+24(FP), R1 // ERROR "invalid MOVH of y_data\+24\(FP\); interface data is 8-byte value"
- MOVW y_data+24(FP), R1 // ERROR "invalid MOVW of y_data\+24\(FP\); interface data is 8-byte value"
- MOVV y_data+24(FP), R1
- RET
-
-TEXT ·returnint(SB),0,$0-8
- MOVB R1, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 8-byte value"
- MOVH R1, ret+0(FP) // ERROR "invalid MOVH of ret\+0\(FP\); int is 8-byte value"
- MOVW R1, ret+0(FP) // ERROR "invalid MOVW of ret\+0\(FP\); int is 8-byte value"
- MOVV R1, ret+0(FP)
- MOVV R1, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)"
- MOVV R1, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)"
- RET
-
-TEXT ·returnbyte(SB),0,$0-9
- MOVV x+0(FP), R1
- MOVB R1, ret+8(FP)
- MOVH R1, ret+8(FP) // ERROR "invalid MOVH of ret\+8\(FP\); byte is 1-byte value"
- MOVW R1, ret+8(FP) // ERROR "invalid MOVW of ret\+8\(FP\); byte is 1-byte value"
- MOVV R1, ret+8(FP) // ERROR "invalid MOVV of ret\+8\(FP\); byte is 1-byte value"
- MOVB R1, ret+7(FP) // ERROR "invalid offset ret\+7\(FP\); expected ret\+8\(FP\)"
- RET
-
-TEXT ·returnnamed(SB),0,$0-41
- MOVB x+0(FP), R1
- MOVV R1, r1+8(FP)
- MOVH R1, r2+16(FP)
- MOVV R1, r3+24(FP)
- MOVV R1, r3_base+24(FP)
- MOVV R1, r3_len+32(FP)
- MOVB R1, r4+40(FP)
- MOVW R1, r1+8(FP) // ERROR "invalid MOVW of r1\+8\(FP\); int is 8-byte value"
- RET
-
-TEXT ·returnintmissing(SB),0,$0-8
- RET // ERROR "RET without writing to 8-byte ret\+0\(FP\)"
diff --git a/libgo/go/cmd/vet/testdata/asm/asm6.s b/libgo/go/cmd/vet/testdata/asm/asm6.s
deleted file mode 100644
index 4e85ab3dcf9..00000000000
--- a/libgo/go/cmd/vet/testdata/asm/asm6.s
+++ /dev/null
@@ -1,193 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build s390x
-// +build vet_test
-
-TEXT ·arg1(SB),0,$0-2
- MOVB x+0(FP), R1
- MOVBZ y+1(FP), R2
- MOVH x+0(FP), R1 // ERROR "\[s390x\] arg1: invalid MOVH of x\+0\(FP\); int8 is 1-byte value"
- MOVHZ y+1(FP), R1 // ERROR "invalid MOVHZ of y\+1\(FP\); uint8 is 1-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
- MOVWZ y+1(FP), R1 // ERROR "invalid MOVWZ of y\+1\(FP\); uint8 is 1-byte value"
- MOVD x+0(FP), R1 // ERROR "invalid MOVD of x\+0\(FP\); int8 is 1-byte value"
- MOVD y+1(FP), R1 // ERROR "invalid MOVD of y\+1\(FP\); uint8 is 1-byte value"
- MOVB x+1(FP), R1 // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
- MOVBZ y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
- MOVB 16(R15), R1 // ERROR "16\(R15\) should be x\+0\(FP\)"
- MOVB 17(R15), R1 // ERROR "17\(R15\) should be y\+1\(FP\)"
- MOVB 18(R15), R1 // ERROR "use of 18\(R15\) points beyond argument frame"
- RET
-
-TEXT ·arg2(SB),0,$0-4
- MOVBZ x+0(FP), R1 // ERROR "arg2: invalid MOVBZ of x\+0\(FP\); int16 is 2-byte value"
- MOVB y+2(FP), R1 // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
- MOVHZ x+0(FP), R1
- MOVH y+2(FP), R2
- MOVWZ x+0(FP), R1 // ERROR "invalid MOVWZ of x\+0\(FP\); int16 is 2-byte value"
- MOVW y+2(FP), R1 // ERROR "invalid MOVW of y\+2\(FP\); uint16 is 2-byte value"
- MOVD x+0(FP), R1 // ERROR "invalid MOVD of x\+0\(FP\); int16 is 2-byte value"
- MOVD y+2(FP), R1 // ERROR "invalid MOVD of y\+2\(FP\); uint16 is 2-byte value"
- MOVHZ x+2(FP), R1 // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
- MOVH y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
- RET
-
-TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8"
- MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
- MOVB y+4(FP), R2 // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int32 is 4-byte value"
- MOVH y+4(FP), R1 // ERROR "invalid MOVH of y\+4\(FP\); uint32 is 4-byte value"
- MOVW x+0(FP), R1
- MOVW y+4(FP), R1
- MOVD x+0(FP), R1 // ERROR "invalid MOVD of x\+0\(FP\); int32 is 4-byte value"
- MOVD y+4(FP), R1 // ERROR "invalid MOVD of y\+4\(FP\); uint32 is 4-byte value"
- MOVW x+4(FP), R1 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVW y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- RET
-
-TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
- MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
- MOVB y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int64 is 8-byte value"
- MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); uint64 is 8-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value"
- MOVW y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value"
- MOVD x+0(FP), R1
- MOVD y+8(FP), R1
- MOVD x+8(FP), R1 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVD y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- RET
-
-TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
- MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int is 8-byte value"
- MOVB y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); uint is 8-byte value"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int is 8-byte value"
- MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); uint is 8-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int is 8-byte value"
- MOVW y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); uint is 8-byte value"
- MOVD x+0(FP), R1
- MOVD y+8(FP), R1
- MOVD x+8(FP), R1 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVD y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- RET
-
-TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-40"
- MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 8-byte value"
- MOVB y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); \*byte is 8-byte value"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); \*byte is 8-byte value"
- MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); \*byte is 8-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); \*byte is 8-byte value"
- MOVW y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); \*byte is 8-byte value"
- MOVD x+0(FP), R1
- MOVD y+8(FP), R1
- MOVD x+8(FP), R1 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVD y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- MOVW c+16(FP), R1 // ERROR "invalid MOVW of c\+16\(FP\); chan int is 8-byte value"
- MOVW m+24(FP), R1 // ERROR "invalid MOVW of m\+24\(FP\); map\[int\]int is 8-byte value"
- MOVW f+32(FP), R1 // ERROR "invalid MOVW of f\+32\(FP\); func\(\) is 8-byte value"
- RET
-
-TEXT ·argstring(SB),0,$32 // ERROR "wrong argument size 0; expected \$\.\.\.-32"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); string base is 8-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); string base is 8-byte value"
- MOVD x+0(FP), R1
- MOVH x_base+0(FP), R1 // ERROR "invalid MOVH of x_base\+0\(FP\); string base is 8-byte value"
- MOVW x_base+0(FP), R1 // ERROR "invalid MOVW of x_base\+0\(FP\); string base is 8-byte value"
- MOVD x_base+0(FP), R1
- MOVH x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVW x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVD x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVH x_len+8(FP), R1 // ERROR "invalid MOVH of x_len\+8\(FP\); string len is 8-byte value"
- MOVW x_len+8(FP), R1 // ERROR "invalid MOVW of x_len\+8\(FP\); string len is 8-byte value"
- MOVD x_len+8(FP), R1
- MOVD y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+16\(FP\)"
- MOVD y_len+8(FP), R1 // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+24\(FP\)"
- RET
-
-TEXT ·argslice(SB),0,$48 // ERROR "wrong argument size 0; expected \$\.\.\.-48"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); slice base is 8-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); slice base is 8-byte value"
- MOVD x+0(FP), R1
- MOVH x_base+0(FP), R1 // ERROR "invalid MOVH of x_base\+0\(FP\); slice base is 8-byte value"
- MOVW x_base+0(FP), R1 // ERROR "invalid MOVW of x_base\+0\(FP\); slice base is 8-byte value"
- MOVD x_base+0(FP), R1
- MOVH x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVW x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVD x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVH x_len+8(FP), R1 // ERROR "invalid MOVH of x_len\+8\(FP\); slice len is 8-byte value"
- MOVW x_len+8(FP), R1 // ERROR "invalid MOVW of x_len\+8\(FP\); slice len is 8-byte value"
- MOVD x_len+8(FP), R1
- MOVH x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVW x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVD x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVH x_cap+16(FP), R1 // ERROR "invalid MOVH of x_cap\+16\(FP\); slice cap is 8-byte value"
- MOVW x_cap+16(FP), R1 // ERROR "invalid MOVW of x_cap\+16\(FP\); slice cap is 8-byte value"
- MOVD x_cap+16(FP), R1
- MOVD y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+24\(FP\)"
- MOVD y_len+8(FP), R1 // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+32\(FP\)"
- MOVD y_cap+16(FP), R1 // ERROR "invalid offset y_cap\+16\(FP\); expected y_cap\+40\(FP\)"
- RET
-
-TEXT ·argiface(SB),0,$0-32
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); interface type is 8-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); interface type is 8-byte value"
- MOVD x+0(FP), R1
- MOVH x_type+0(FP), R1 // ERROR "invalid MOVH of x_type\+0\(FP\); interface type is 8-byte value"
- MOVW x_type+0(FP), R1 // ERROR "invalid MOVW of x_type\+0\(FP\); interface type is 8-byte value"
- MOVD x_type+0(FP), R1
- MOVD x_itable+0(FP), R1 // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
- MOVD x_itable+1(FP), R1 // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
- MOVH x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVW x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVD x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVH x_data+8(FP), R1 // ERROR "invalid MOVH of x_data\+8\(FP\); interface data is 8-byte value"
- MOVW x_data+8(FP), R1 // ERROR "invalid MOVW of x_data\+8\(FP\); interface data is 8-byte value"
- MOVD x_data+8(FP), R1
- MOVH y+16(FP), R1 // ERROR "invalid MOVH of y\+16\(FP\); interface itable is 8-byte value"
- MOVW y+16(FP), R1 // ERROR "invalid MOVW of y\+16\(FP\); interface itable is 8-byte value"
- MOVD y+16(FP), R1
- MOVH y_itable+16(FP), R1 // ERROR "invalid MOVH of y_itable\+16\(FP\); interface itable is 8-byte value"
- MOVW y_itable+16(FP), R1 // ERROR "invalid MOVW of y_itable\+16\(FP\); interface itable is 8-byte value"
- MOVD y_itable+16(FP), R1
- MOVD y_type+16(FP), R1 // ERROR "unknown variable y_type; offset 16 is y_itable\+16\(FP\)"
- MOVH y_data+16(FP), R1 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVW y_data+16(FP), R1 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVD y_data+16(FP), R1 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVH y_data+24(FP), R1 // ERROR "invalid MOVH of y_data\+24\(FP\); interface data is 8-byte value"
- MOVW y_data+24(FP), R1 // ERROR "invalid MOVW of y_data\+24\(FP\); interface data is 8-byte value"
- MOVD y_data+24(FP), R1
- RET
-
-TEXT ·returnint(SB),0,$0-8
- MOVB R1, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 8-byte value"
- MOVH R1, ret+0(FP) // ERROR "invalid MOVH of ret\+0\(FP\); int is 8-byte value"
- MOVW R1, ret+0(FP) // ERROR "invalid MOVW of ret\+0\(FP\); int is 8-byte value"
- MOVD R1, ret+0(FP)
- MOVD R1, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)"
- MOVD R1, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)"
- RET
-
-TEXT ·returnbyte(SB),0,$0-9
- MOVD x+0(FP), R1
- MOVB R1, ret+8(FP)
- MOVH R1, ret+8(FP) // ERROR "invalid MOVH of ret\+8\(FP\); byte is 1-byte value"
- MOVW R1, ret+8(FP) // ERROR "invalid MOVW of ret\+8\(FP\); byte is 1-byte value"
- MOVD R1, ret+8(FP) // ERROR "invalid MOVD of ret\+8\(FP\); byte is 1-byte value"
- MOVB R1, ret+7(FP) // ERROR "invalid offset ret\+7\(FP\); expected ret\+8\(FP\)"
- RET
-
-TEXT ·returnnamed(SB),0,$0-41
- MOVB x+0(FP), R1
- MOVD R1, r1+8(FP)
- MOVH R1, r2+16(FP)
- MOVD R1, r3+24(FP)
- MOVD R1, r3_base+24(FP)
- MOVD R1, r3_len+32(FP)
- MOVB R1, r4+40(FP)
- MOVW R1, r1+8(FP) // ERROR "invalid MOVW of r1\+8\(FP\); int is 8-byte value"
- RET
-
-TEXT ·returnintmissing(SB),0,$0-8
- RET // ERROR "RET without writing to 8-byte ret\+0\(FP\)"
diff --git a/libgo/go/cmd/vet/testdata/asm/asm7.s b/libgo/go/cmd/vet/testdata/asm/asm7.s
deleted file mode 100644
index d5ff5460a56..00000000000
--- a/libgo/go/cmd/vet/testdata/asm/asm7.s
+++ /dev/null
@@ -1,193 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ppc64 ppc64le
-// +build vet_test
-
-TEXT ·arg1(SB),0,$0-2
- MOVB x+0(FP), R3
- MOVBZ y+1(FP), R4
- MOVH x+0(FP), R3 // ERROR "\[(ppc64|ppc64le)\] arg1: invalid MOVH of x\+0\(FP\); int8 is 1-byte value"
- MOVHZ y+1(FP), R3 // ERROR "invalid MOVHZ of y\+1\(FP\); uint8 is 1-byte value"
- MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
- MOVWZ y+1(FP), R3 // ERROR "invalid MOVWZ of y\+1\(FP\); uint8 is 1-byte value"
- MOVD x+0(FP), R3 // ERROR "invalid MOVD of x\+0\(FP\); int8 is 1-byte value"
- MOVD y+1(FP), R3 // ERROR "invalid MOVD of y\+1\(FP\); uint8 is 1-byte value"
- MOVB x+1(FP), R3 // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
- MOVBZ y+2(FP), R3 // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
- MOVB 16(R1), R3 // ERROR "16\(R1\) should be x\+0\(FP\)"
- MOVB 17(R1), R3 // ERROR "17\(R1\) should be y\+1\(FP\)"
- MOVB 18(R1), R3 // ERROR "use of 18\(R1\) points beyond argument frame"
- RET
-
-TEXT ·arg2(SB),0,$0-4
- MOVBZ x+0(FP), R3 // ERROR "arg2: invalid MOVBZ of x\+0\(FP\); int16 is 2-byte value"
- MOVB y+2(FP), R3 // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
- MOVHZ x+0(FP), R3
- MOVH y+2(FP), R4
- MOVWZ x+0(FP), R3 // ERROR "invalid MOVWZ of x\+0\(FP\); int16 is 2-byte value"
- MOVW y+2(FP), R3 // ERROR "invalid MOVW of y\+2\(FP\); uint16 is 2-byte value"
- MOVD x+0(FP), R3 // ERROR "invalid MOVD of x\+0\(FP\); int16 is 2-byte value"
- MOVD y+2(FP), R3 // ERROR "invalid MOVD of y\+2\(FP\); uint16 is 2-byte value"
- MOVHZ x+2(FP), R3 // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
- MOVH y+0(FP), R3 // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
- RET
-
-TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8"
- MOVB x+0(FP), R3 // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
- MOVB y+4(FP), R4 // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
- MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); int32 is 4-byte value"
- MOVH y+4(FP), R3 // ERROR "invalid MOVH of y\+4\(FP\); uint32 is 4-byte value"
- MOVW x+0(FP), R3
- MOVW y+4(FP), R3
- MOVD x+0(FP), R3 // ERROR "invalid MOVD of x\+0\(FP\); int32 is 4-byte value"
- MOVD y+4(FP), R3 // ERROR "invalid MOVD of y\+4\(FP\); uint32 is 4-byte value"
- MOVW x+4(FP), R3 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVW y+2(FP), R3 // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- RET
-
-TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
- MOVB x+0(FP), R3 // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
- MOVB y+8(FP), R4 // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
- MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); int64 is 8-byte value"
- MOVH y+8(FP), R3 // ERROR "invalid MOVH of y\+8\(FP\); uint64 is 8-byte value"
- MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value"
- MOVW y+8(FP), R3 // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value"
- MOVD x+0(FP), R3
- MOVD y+8(FP), R3
- MOVD x+8(FP), R3 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVD y+2(FP), R3 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- RET
-
-TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
- MOVB x+0(FP), R3 // ERROR "invalid MOVB of x\+0\(FP\); int is 8-byte value"
- MOVB y+8(FP), R4 // ERROR "invalid MOVB of y\+8\(FP\); uint is 8-byte value"
- MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); int is 8-byte value"
- MOVH y+8(FP), R3 // ERROR "invalid MOVH of y\+8\(FP\); uint is 8-byte value"
- MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); int is 8-byte value"
- MOVW y+8(FP), R3 // ERROR "invalid MOVW of y\+8\(FP\); uint is 8-byte value"
- MOVD x+0(FP), R3
- MOVD y+8(FP), R3
- MOVD x+8(FP), R3 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVD y+2(FP), R3 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- RET
-
-TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-40"
- MOVB x+0(FP), R3 // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 8-byte value"
- MOVB y+8(FP), R4 // ERROR "invalid MOVB of y\+8\(FP\); \*byte is 8-byte value"
- MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); \*byte is 8-byte value"
- MOVH y+8(FP), R3 // ERROR "invalid MOVH of y\+8\(FP\); \*byte is 8-byte value"
- MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); \*byte is 8-byte value"
- MOVW y+8(FP), R3 // ERROR "invalid MOVW of y\+8\(FP\); \*byte is 8-byte value"
- MOVD x+0(FP), R3
- MOVD y+8(FP), R3
- MOVD x+8(FP), R3 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVD y+2(FP), R3 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- MOVW c+16(FP), R3 // ERROR "invalid MOVW of c\+16\(FP\); chan int is 8-byte value"
- MOVW m+24(FP), R3 // ERROR "invalid MOVW of m\+24\(FP\); map\[int\]int is 8-byte value"
- MOVW f+32(FP), R3 // ERROR "invalid MOVW of f\+32\(FP\); func\(\) is 8-byte value"
- RET
-
-TEXT ·argstring(SB),0,$32 // ERROR "wrong argument size 0; expected \$\.\.\.-32"
- MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); string base is 8-byte value"
- MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); string base is 8-byte value"
- MOVD x+0(FP), R3
- MOVH x_base+0(FP), R3 // ERROR "invalid MOVH of x_base\+0\(FP\); string base is 8-byte value"
- MOVW x_base+0(FP), R3 // ERROR "invalid MOVW of x_base\+0\(FP\); string base is 8-byte value"
- MOVD x_base+0(FP), R3
- MOVH x_len+0(FP), R3 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVW x_len+0(FP), R3 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVD x_len+0(FP), R3 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVH x_len+8(FP), R3 // ERROR "invalid MOVH of x_len\+8\(FP\); string len is 8-byte value"
- MOVW x_len+8(FP), R3 // ERROR "invalid MOVW of x_len\+8\(FP\); string len is 8-byte value"
- MOVD x_len+8(FP), R3
- MOVD y+0(FP), R3 // ERROR "invalid offset y\+0\(FP\); expected y\+16\(FP\)"
- MOVD y_len+8(FP), R3 // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+24\(FP\)"
- RET
-
-TEXT ·argslice(SB),0,$48 // ERROR "wrong argument size 0; expected \$\.\.\.-48"
- MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); slice base is 8-byte value"
- MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); slice base is 8-byte value"
- MOVD x+0(FP), R3
- MOVH x_base+0(FP), R3 // ERROR "invalid MOVH of x_base\+0\(FP\); slice base is 8-byte value"
- MOVW x_base+0(FP), R3 // ERROR "invalid MOVW of x_base\+0\(FP\); slice base is 8-byte value"
- MOVD x_base+0(FP), R3
- MOVH x_len+0(FP), R3 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVW x_len+0(FP), R3 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVD x_len+0(FP), R3 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVH x_len+8(FP), R3 // ERROR "invalid MOVH of x_len\+8\(FP\); slice len is 8-byte value"
- MOVW x_len+8(FP), R3 // ERROR "invalid MOVW of x_len\+8\(FP\); slice len is 8-byte value"
- MOVD x_len+8(FP), R3
- MOVH x_cap+0(FP), R3 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVW x_cap+0(FP), R3 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVD x_cap+0(FP), R3 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVH x_cap+16(FP), R3 // ERROR "invalid MOVH of x_cap\+16\(FP\); slice cap is 8-byte value"
- MOVW x_cap+16(FP), R3 // ERROR "invalid MOVW of x_cap\+16\(FP\); slice cap is 8-byte value"
- MOVD x_cap+16(FP), R3
- MOVD y+0(FP), R3 // ERROR "invalid offset y\+0\(FP\); expected y\+24\(FP\)"
- MOVD y_len+8(FP), R3 // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+32\(FP\)"
- MOVD y_cap+16(FP), R3 // ERROR "invalid offset y_cap\+16\(FP\); expected y_cap\+40\(FP\)"
- RET
-
-TEXT ·argiface(SB),0,$0-32
- MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); interface type is 8-byte value"
- MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); interface type is 8-byte value"
- MOVD x+0(FP), R3
- MOVH x_type+0(FP), R3 // ERROR "invalid MOVH of x_type\+0\(FP\); interface type is 8-byte value"
- MOVW x_type+0(FP), R3 // ERROR "invalid MOVW of x_type\+0\(FP\); interface type is 8-byte value"
- MOVD x_type+0(FP), R3
- MOVD x_itable+0(FP), R3 // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
- MOVD x_itable+1(FP), R3 // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
- MOVH x_data+0(FP), R3 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVW x_data+0(FP), R3 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVD x_data+0(FP), R3 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVH x_data+8(FP), R3 // ERROR "invalid MOVH of x_data\+8\(FP\); interface data is 8-byte value"
- MOVW x_data+8(FP), R3 // ERROR "invalid MOVW of x_data\+8\(FP\); interface data is 8-byte value"
- MOVD x_data+8(FP), R3
- MOVH y+16(FP), R3 // ERROR "invalid MOVH of y\+16\(FP\); interface itable is 8-byte value"
- MOVW y+16(FP), R3 // ERROR "invalid MOVW of y\+16\(FP\); interface itable is 8-byte value"
- MOVD y+16(FP), R3
- MOVH y_itable+16(FP), R3 // ERROR "invalid MOVH of y_itable\+16\(FP\); interface itable is 8-byte value"
- MOVW y_itable+16(FP), R3 // ERROR "invalid MOVW of y_itable\+16\(FP\); interface itable is 8-byte value"
- MOVD y_itable+16(FP), R3
- MOVD y_type+16(FP), R3 // ERROR "unknown variable y_type; offset 16 is y_itable\+16\(FP\)"
- MOVH y_data+16(FP), R3 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVW y_data+16(FP), R3 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVD y_data+16(FP), R3 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVH y_data+24(FP), R3 // ERROR "invalid MOVH of y_data\+24\(FP\); interface data is 8-byte value"
- MOVW y_data+24(FP), R3 // ERROR "invalid MOVW of y_data\+24\(FP\); interface data is 8-byte value"
- MOVD y_data+24(FP), R3
- RET
-
-TEXT ·returnint(SB),0,$0-8
- MOVB R3, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 8-byte value"
- MOVH R3, ret+0(FP) // ERROR "invalid MOVH of ret\+0\(FP\); int is 8-byte value"
- MOVW R3, ret+0(FP) // ERROR "invalid MOVW of ret\+0\(FP\); int is 8-byte value"
- MOVD R3, ret+0(FP)
- MOVD R3, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)"
- MOVD R3, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)"
- RET
-
-TEXT ·returnbyte(SB),0,$0-9
- MOVD x+0(FP), R3
- MOVB R3, ret+8(FP)
- MOVH R3, ret+8(FP) // ERROR "invalid MOVH of ret\+8\(FP\); byte is 1-byte value"
- MOVW R3, ret+8(FP) // ERROR "invalid MOVW of ret\+8\(FP\); byte is 1-byte value"
- MOVD R3, ret+8(FP) // ERROR "invalid MOVD of ret\+8\(FP\); byte is 1-byte value"
- MOVB R3, ret+7(FP) // ERROR "invalid offset ret\+7\(FP\); expected ret\+8\(FP\)"
- RET
-
-TEXT ·returnnamed(SB),0,$0-41
- MOVB x+0(FP), R3
- MOVD R3, r1+8(FP)
- MOVH R3, r2+16(FP)
- MOVD R3, r3+24(FP)
- MOVD R3, r3_base+24(FP)
- MOVD R3, r3_len+32(FP)
- MOVB R3, r4+40(FP)
- MOVW R3, r1+8(FP) // ERROR "invalid MOVW of r1\+8\(FP\); int is 8-byte value"
- RET
-
-TEXT ·returnintmissing(SB),0,$0-8
- RET // ERROR "RET without writing to 8-byte ret\+0\(FP\)"
diff --git a/libgo/go/cmd/vet/testdata/asm8.s b/libgo/go/cmd/vet/testdata/asm8.s
deleted file mode 100644
index 550d92a8d2d..00000000000
--- a/libgo/go/cmd/vet/testdata/asm8.s
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build mipsle
-// +build vet_test
-
-TEXT ·arg1(SB),0,$0-2
- MOVB x+0(FP), R1
- MOVBU y+1(FP), R2
- MOVH x+0(FP), R1 // ERROR "\[mipsle\] arg1: invalid MOVH of x\+0\(FP\); int8 is 1-byte value"
- MOVHU y+1(FP), R1 // ERROR "invalid MOVHU of y\+1\(FP\); uint8 is 1-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
- MOVWU y+1(FP), R1 // ERROR "invalid MOVWU of y\+1\(FP\); uint8 is 1-byte value"
- MOVW y+1(FP), R1 // ERROR "invalid MOVW of y\+1\(FP\); uint8 is 1-byte value"
- MOVB x+1(FP), R1 // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
- MOVBU y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
- MOVB 8(R29), R1 // ERROR "8\(R29\) should be x\+0\(FP\)"
- MOVB 9(R29), R1 // ERROR "9\(R29\) should be y\+1\(FP\)"
- MOVB 10(R29), R1 // ERROR "use of 10\(R29\) points beyond argument frame"
- RET
-
-TEXT ·arg2(SB),0,$0-4
- MOVBU x+0(FP), R1 // ERROR "arg2: invalid MOVBU of x\+0\(FP\); int16 is 2-byte value"
- MOVB y+2(FP), R1 // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
- MOVHU x+0(FP), R1
- MOVH y+2(FP), R2
- MOVWU x+0(FP), R1 // ERROR "invalid MOVWU of x\+0\(FP\); int16 is 2-byte value"
- MOVW y+2(FP), R1 // ERROR "invalid MOVW of y\+2\(FP\); uint16 is 2-byte value"
- MOVHU x+2(FP), R1 // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
- MOVH y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
- RET
-
-TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8"
- MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
- MOVB y+4(FP), R2 // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int32 is 4-byte value"
- MOVH y+4(FP), R1 // ERROR "invalid MOVH of y\+4\(FP\); uint32 is 4-byte value"
- MOVW x+0(FP), R1
- MOVW y+4(FP), R1
- MOVW x+4(FP), R1 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVW y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- RET
-
-TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
- MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
- MOVB y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int64 is 8-byte value"
- MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); uint64 is 8-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value containing x_lo\+0\(FP\) and x_hi\+4\(FP\)"
- MOVW x_lo+0(FP), R1
- MOVW x_hi+4(FP), R1
- MOVW y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value containing y_lo\+8\(FP\) and y_hi\+12\(FP\)"
- MOVW y_lo+8(FP), R1
- MOVW y_hi+12(FP), R1
- RET
-
-TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-8"
- MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int is 4-byte value"
- MOVB y+4(FP), R2 // ERROR "invalid MOVB of y\+4\(FP\); uint is 4-byte value"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int is 4-byte value"
- MOVH y+4(FP), R1 // ERROR "invalid MOVH of y\+4\(FP\); uint is 4-byte value"
- MOVW x+0(FP), R1
- MOVW y+4(FP), R1
- MOVW x+4(FP), R1 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVW y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- RET
-
-TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-20"
- MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 4-byte value"
- MOVB y+4(FP), R2 // ERROR "invalid MOVB of y\+4\(FP\); \*byte is 4-byte value"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); \*byte is 4-byte value"
- MOVH y+4(FP), R1 // ERROR "invalid MOVH of y\+4\(FP\); \*byte is 4-byte value"
- MOVW x+0(FP), R1
- MOVW y+4(FP), R1
- MOVW x+4(FP), R1 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVW y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- MOVH c+8(FP), R1 // ERROR "invalid MOVH of c\+8\(FP\); chan int is 4-byte value"
- MOVH m+12(FP), R1 // ERROR "invalid MOVH of m\+12\(FP\); map\[int\]int is 4-byte value"
- MOVH f+16(FP), R1 // ERROR "invalid MOVH of f\+16\(FP\); func\(\) is 4-byte value"
- RET
-
-TEXT ·argstring(SB),0,$16 // ERROR "wrong argument size 0; expected \$\.\.\.-16"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); string base is 4-byte value"
- MOVW x+0(FP), R1
- MOVH x_base+0(FP), R1 // ERROR "invalid MOVH of x_base\+0\(FP\); string base is 4-byte value"
- MOVW x_base+0(FP), R1
- MOVH x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVW x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVH x_len+4(FP), R1 // ERROR "invalid MOVH of x_len\+4\(FP\); string len is 4-byte value"
- MOVW x_len+4(FP), R1
- MOVW y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+8\(FP\)"
- MOVW y_len+4(FP), R1 // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+12\(FP\)"
- RET
-
-TEXT ·argslice(SB),0,$24 // ERROR "wrong argument size 0; expected \$\.\.\.-24"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); slice base is 4-byte value"
- MOVW x+0(FP), R1
- MOVH x_base+0(FP), R1 // ERROR "invalid MOVH of x_base\+0\(FP\); slice base is 4-byte value"
- MOVW x_base+0(FP), R1
- MOVH x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVW x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVH x_len+4(FP), R1 // ERROR "invalid MOVH of x_len\+4\(FP\); slice len is 4-byte value"
- MOVW x_len+4(FP), R1
- MOVH x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
- MOVW x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
- MOVH x_cap+8(FP), R1 // ERROR "invalid MOVH of x_cap\+8\(FP\); slice cap is 4-byte value"
- MOVW x_cap+8(FP), R1
- MOVW y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+12\(FP\)"
- MOVW y_len+4(FP), R1 // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+16\(FP\)"
- MOVW y_cap+8(FP), R1 // ERROR "invalid offset y_cap\+8\(FP\); expected y_cap\+20\(FP\)"
- RET
-
-TEXT ·argiface(SB),0,$0-16
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); interface type is 4-byte value"
- MOVW x+0(FP), R1
- MOVH x_type+0(FP), R1 // ERROR "invalid MOVH of x_type\+0\(FP\); interface type is 4-byte value"
- MOVW x_type+0(FP), R1
- MOVQ x_itable+0(FP), R1 // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
- MOVQ x_itable+1(FP), R1 // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
- MOVH x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
- MOVW x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
- MOVQ x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
- MOVH x_data+4(FP), R1 // ERROR "invalid MOVH of x_data\+4\(FP\); interface data is 4-byte value"
- MOVW x_data+4(FP), R1
- MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); interface itable is 4-byte value"
- MOVW y+8(FP), R1
- MOVH y_itable+8(FP), R1 // ERROR "invalid MOVH of y_itable\+8\(FP\); interface itable is 4-byte value"
- MOVW y_itable+8(FP), R1
- MOVW y_type+8(FP), AX // ERROR "unknown variable y_type; offset 8 is y_itable\+8\(FP\)"
- MOVH y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
- MOVW y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
- MOVH y_data+12(FP), AX // ERROR "invalid MOVH of y_data\+12\(FP\); interface data is 4-byte value"
- MOVW y_data+12(FP), AX
- RET
-
-TEXT ·returnbyte(SB),0,$0-5
- MOVW x+0(FP), R1
- MOVB R1, ret+4(FP)
- MOVH R1, ret+4(FP) // ERROR "invalid MOVH of ret\+4\(FP\); byte is 1-byte value"
- MOVW R1, ret+4(FP) // ERROR "invalid MOVW of ret\+4\(FP\); byte is 1-byte value"
- MOVB R1, ret+3(FP) // ERROR "invalid offset ret\+3\(FP\); expected ret\+4\(FP\)"
- RET
-
-TEXT ·returnbyte(SB),0,$0-5
- MOVW x+0(FP), R1
- MOVB R1, ret+4(FP)
- MOVH R1, ret+4(FP) // ERROR "invalid MOVH of ret\+4\(FP\); byte is 1-byte value"
- MOVW R1, ret+4(FP) // ERROR "invalid MOVW of ret\+4\(FP\); byte is 1-byte value"
- MOVB R1, ret+3(FP) // ERROR "invalid offset ret\+3\(FP\); expected ret\+4\(FP\)"
- RET
-
-TEXT ·returnnamed(SB),0,$0-21
- MOVB x+0(FP), AX
- MOVW R1, r1+4(FP)
- MOVH R1, r2+8(FP)
- MOVW R1, r3+12(FP)
- MOVW R1, r3_base+12(FP)
- MOVW R1, r3_len+16(FP)
- MOVB R1, r4+20(FP)
- MOVB R1, r1+4(FP) // ERROR "invalid MOVB of r1\+4\(FP\); int is 4-byte value"
- RET
-
-TEXT ·returnintmissing(SB),0,$0-4
- RET // ERROR "RET without writing to 4-byte ret\+0\(FP\)"
diff --git a/libgo/go/cmd/vet/testdata/atomic.go b/libgo/go/cmd/vet/testdata/atomic.go
deleted file mode 100644
index 69730b4e6f0..00000000000
--- a/libgo/go/cmd/vet/testdata/atomic.go
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file contains tests for the atomic checker.
-
-package testdata
-
-import (
- "sync/atomic"
-)
-
-type Counter uint64
-
-func AtomicTests() {
- x := uint64(1)
- x = atomic.AddUint64(&x, 1) // ERROR "direct assignment to atomic value"
- _, x = 10, atomic.AddUint64(&x, 1) // ERROR "direct assignment to atomic value"
- x, _ = atomic.AddUint64(&x, 1), 10 // ERROR "direct assignment to atomic value"
-
- y := &x
- *y = atomic.AddUint64(y, 1) // ERROR "direct assignment to atomic value"
-
- var su struct{ Counter uint64 }
- su.Counter = atomic.AddUint64(&su.Counter, 1) // ERROR "direct assignment to atomic value"
- z1 := atomic.AddUint64(&su.Counter, 1)
- _ = z1 // Avoid err "z declared and not used"
-
- var sp struct{ Counter *uint64 }
- *sp.Counter = atomic.AddUint64(sp.Counter, 1) // ERROR "direct assignment to atomic value"
- z2 := atomic.AddUint64(sp.Counter, 1)
- _ = z2 // Avoid err "z declared and not used"
-
- au := []uint64{10, 20}
- au[0] = atomic.AddUint64(&au[0], 1) // ERROR "direct assignment to atomic value"
- au[1] = atomic.AddUint64(&au[0], 1)
-
- ap := []*uint64{&au[0], &au[1]}
- *ap[0] = atomic.AddUint64(ap[0], 1) // ERROR "direct assignment to atomic value"
- *ap[1] = atomic.AddUint64(ap[0], 1)
-
- x = atomic.AddUint64() // Used to make vet crash; now silently ignored.
-
- {
- // A variable declaration creates a new variable in the current scope.
- x := atomic.AddUint64(&x, 1) // ERROR "declaration of .x. shadows declaration at atomic.go:16"
-
- // Re-declaration assigns a new value.
- x, w := atomic.AddUint64(&x, 1), 10 // ERROR "direct assignment to atomic value"
- _ = w
- }
-}
-
-type T struct{}
-
-func (T) AddUint64(addr *uint64, delta uint64) uint64 { return 0 }
-
-func NonAtomic() {
- x := uint64(1)
- var atomic T
- x = atomic.AddUint64(&x, 1) // ok; not the imported pkg
-}
diff --git a/libgo/go/cmd/vet/testdata/bool.go b/libgo/go/cmd/vet/testdata/bool.go
deleted file mode 100644
index 80c44d25ca3..00000000000
--- a/libgo/go/cmd/vet/testdata/bool.go
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file contains tests for the bool checker.
-
-package testdata
-
-import "io"
-
-type T int
-
-func (t T) Foo() int { return int(t) }
-
-type FT func() int
-
-var S []int
-
-func RatherStupidConditions() {
- var f, g func() int
- if f() == 0 || f() == 0 { // OK f might have side effects
- }
- var t T
- _ = t.Foo() == 2 || t.Foo() == 2 // OK Foo might have side effects
- if v, w := f(), g(); v == w || v == w { // ERROR "redundant or: v == w || v == w"
- }
- _ = f == nil || f == nil // ERROR "redundant or: f == nil || f == nil"
-
- _ = i == byte(1) || i == byte(1) // ERROR "redundant or: i == byte(1) || i == byte(1)"
- _ = i == T(2) || i == T(2) // ERROR "redundant or: i == T(2) || i == T(2)"
- _ = FT(f) == nil || FT(f) == nil // ERROR "redundant or: FT(f) == nil || FT(f) == nil"
-
- _ = (func() int)(f) == nil || (func() int)(f) == nil // ERROR "redundant or: (func() int)(f) == nil || (func() int)(f) == nil"
- _ = append(S, 3) == nil || append(S, 3) == nil // OK append has side effects
-
- var namedFuncVar FT
- _ = namedFuncVar() == namedFuncVar() // OK still func calls
-
- var c chan int
- _ = 0 == <-c || 0 == <-c // OK subsequent receives may yield different values
- for i, j := <-c, <-c; i == j || i == j; i, j = <-c, <-c { // ERROR "redundant or: i == j || i == j"
- }
-
- var i, j, k int
- _ = i+1 == 1 || i+1 == 1 // ERROR "redundant or: i\+1 == 1 || i\+1 == 1"
- _ = i == 1 || j+1 == i || i == 1 // ERROR "redundant or: i == 1 || i == 1"
-
- _ = i == 1 || i == 1 || f() == 1 // ERROR "redundant or: i == 1 || i == 1"
- _ = i == 1 || f() == 1 || i == 1 // OK f may alter i as a side effect
- _ = f() == 1 || i == 1 || i == 1 // ERROR "redundant or: i == 1 || i == 1"
-
- // Test partition edge cases
- _ = f() == 1 || i == 1 || i == 1 || j == 1 // ERROR "redundant or: i == 1 || i == 1"
- _ = f() == 1 || j == 1 || i == 1 || i == 1 // ERROR "redundant or: i == 1 || i == 1"
- _ = i == 1 || f() == 1 || i == 1 || i == 1 // ERROR "redundant or: i == 1 || i == 1"
- _ = i == 1 || i == 1 || f() == 1 || i == 1 // ERROR "redundant or: i == 1 || i == 1"
- _ = i == 1 || i == 1 || j == 1 || f() == 1 // ERROR "redundant or: i == 1 || i == 1"
- _ = j == 1 || i == 1 || i == 1 || f() == 1 // ERROR "redundant or: i == 1 || i == 1"
- _ = i == 1 || f() == 1 || f() == 1 || i == 1
-
- _ = i == 1 || (i == 1 || i == 2) // ERROR "redundant or: i == 1 || i == 1"
- _ = i == 1 || (f() == 1 || i == 1) // OK f may alter i as a side effect
- _ = i == 1 || (i == 1 || f() == 1) // ERROR "redundant or: i == 1 || i == 1"
- _ = i == 1 || (i == 2 || (i == 1 || i == 3)) // ERROR "redundant or: i == 1 || i == 1"
-
- var a, b bool
- _ = i == 1 || (a || (i == 1 || b)) // ERROR "redundant or: i == 1 || i == 1"
-
- // Check that all redundant ors are flagged
- _ = j == 0 ||
- i == 1 ||
- f() == 1 ||
- j == 0 || // ERROR "redundant or: j == 0 || j == 0"
- i == 1 || // ERROR "redundant or: i == 1 || i == 1"
- i == 1 || // ERROR "redundant or: i == 1 || i == 1"
- i == 1 ||
- j == 0 ||
- k == 0
-
- _ = i == 1*2*3 || i == 1*2*3 // ERROR "redundant or: i == 1\*2\*3 || i == 1\*2\*3"
-
- // These test that redundant, suspect expressions do not trigger multiple errors.
- _ = i != 0 || i != 0 // ERROR "redundant or: i != 0 || i != 0"
- _ = i == 0 && i == 0 // ERROR "redundant and: i == 0 && i == 0"
-
- // and is dual to or; check the basics and
- // let the or tests pull the rest of the weight.
- _ = 0 != <-c && 0 != <-c // OK subsequent receives may yield different values
- _ = f() != 0 && f() != 0 // OK f might have side effects
- _ = f != nil && f != nil // ERROR "redundant and: f != nil && f != nil"
- _ = i != 1 && i != 1 && f() != 1 // ERROR "redundant and: i != 1 && i != 1"
- _ = i != 1 && f() != 1 && i != 1 // OK f may alter i as a side effect
- _ = f() != 1 && i != 1 && i != 1 // ERROR "redundant and: i != 1 && i != 1"
-}
-
-func RoyallySuspectConditions() {
- var i, j int
-
- _ = i == 0 || i == 1 // OK
- _ = i != 0 || i != 1 // ERROR "suspect or: i != 0 || i != 1"
- _ = i != 0 || 1 != i // ERROR "suspect or: i != 0 || 1 != i"
- _ = 0 != i || 1 != i // ERROR "suspect or: 0 != i || 1 != i"
- _ = 0 != i || i != 1 // ERROR "suspect or: 0 != i || i != 1"
-
- _ = (0 != i) || i != 1 // ERROR "suspect or: 0 != i || i != 1"
-
- _ = i+3 != 7 || j+5 == 0 || i+3 != 9 // ERROR "suspect or: i\+3 != 7 || i\+3 != 9"
-
- _ = i != 0 || j == 0 || i != 1 // ERROR "suspect or: i != 0 || i != 1"
-
- _ = i != 0 || i != 1<<4 // ERROR "suspect or: i != 0 || i != 1<<4"
-
- _ = i != 0 || j != 0
- _ = 0 != i || 0 != j
-
- var s string
- _ = s != "one" || s != "the other" // ERROR "suspect or: s != .one. || s != .the other."
-
- _ = "et" != "alii" || "et" != "cetera" // ERROR "suspect or: .et. != .alii. || .et. != .cetera."
- _ = "me gustas" != "tu" || "le gustas" != "tu" // OK we could catch this case, but it's not worth the code
-
- var err error
- _ = err != nil || err != io.EOF // TODO catch this case?
-
- // Sanity check and.
- _ = i != 0 && i != 1 // OK
- _ = i == 0 && i == 1 // ERROR "suspect and: i == 0 && i == 1"
- _ = i == 0 && 1 == i // ERROR "suspect and: i == 0 && 1 == i"
- _ = 0 == i && 1 == i // ERROR "suspect and: 0 == i && 1 == i"
- _ = 0 == i && i == 1 // ERROR "suspect and: 0 == i && i == 1"
-}
diff --git a/libgo/go/cmd/vet/testdata/buildtag/buildtag_bad.go b/libgo/go/cmd/vet/testdata/buildtag/buildtag_bad.go
deleted file mode 100644
index fbe10cf748f..00000000000
--- a/libgo/go/cmd/vet/testdata/buildtag/buildtag_bad.go
+++ /dev/null
@@ -1,15 +0,0 @@
-// This file contains misplaced or malformed build constraints.
-// The Go tool will skip it, because the constraints are invalid.
-// It serves only to test the tag checker during make test.
-
-// Mention +build // ERROR "possible malformed \+build comment"
-
-// +build !!bang // ERROR "invalid double negative in build constraint"
-// +build @#$ // ERROR "invalid non-alphanumeric build constraint"
-
-// +build toolate // ERROR "build comment must appear before package clause and be followed by a blank line"
-package bad
-
-// This is package 'bad' rather than 'main' so the erroneous build
-// tag doesn't end up looking like a package doc for the vet command
-// when examined by godoc.
diff --git a/libgo/go/cmd/vet/testdata/cgo/cgo.go b/libgo/go/cmd/vet/testdata/cgo/cgo.go
deleted file mode 100644
index d0df7cf6787..00000000000
--- a/libgo/go/cmd/vet/testdata/cgo/cgo.go
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file contains tests for the cgo checker.
-
-package testdata
-
-// void f(void *);
-import "C"
-
-import "unsafe"
-
-func CgoTests() {
- var c chan bool
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&c))) // ERROR "embedded pointer"
- C.f(unsafe.Pointer(&c)) // ERROR "embedded pointer"
-
- var m map[string]string
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&m))) // ERROR "embedded pointer"
- C.f(unsafe.Pointer(&m)) // ERROR "embedded pointer"
-
- var f func()
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&f))) // ERROR "embedded pointer"
- C.f(unsafe.Pointer(&f)) // ERROR "embedded pointer"
-
- var s []int
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&s))) // ERROR "embedded pointer"
- C.f(unsafe.Pointer(&s)) // ERROR "embedded pointer"
-
- var a [1][]int
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&a))) // ERROR "embedded pointer"
- C.f(unsafe.Pointer(&a)) // ERROR "embedded pointer"
-
- var st struct{ f []int }
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&st))) // ERROR "embedded pointer"
- C.f(unsafe.Pointer(&st)) // ERROR "embedded pointer"
-
- // The following cases are OK.
- var i int
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&i)))
- C.f(unsafe.Pointer(&i))
-
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&s[0])))
- C.f(unsafe.Pointer(&s[0]))
-
- var a2 [1]int
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&a2)))
- C.f(unsafe.Pointer(&a2))
-
- var st2 struct{ i int }
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&st2)))
- C.f(unsafe.Pointer(&st2))
-
- type cgoStruct struct{ p *cgoStruct }
- C.f(unsafe.Pointer(&cgoStruct{}))
-
- C.CBytes([]byte("hello"))
-}
diff --git a/libgo/go/cmd/vet/testdata/cgo/cgo2.go b/libgo/go/cmd/vet/testdata/cgo/cgo2.go
deleted file mode 100644
index 4f271168931..00000000000
--- a/libgo/go/cmd/vet/testdata/cgo/cgo2.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Test the cgo checker on a file that doesn't use cgo.
-
-package testdata
-
-var _ = C.f(*p(**p))
-
-// Passing a pointer (via the slice), but C isn't cgo.
-var _ = C.f([]int{3})
diff --git a/libgo/go/cmd/vet/testdata/cgo/cgo3.go b/libgo/go/cmd/vet/testdata/cgo/cgo3.go
deleted file mode 100644
index 0b1518e1f93..00000000000
--- a/libgo/go/cmd/vet/testdata/cgo/cgo3.go
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2017 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Used by TestVetVerbose to test that vet -v doesn't fail because it
-// can't find "C".
-
-package testdata
-
-import "C"
-
-func F() {
-}
diff --git a/libgo/go/cmd/vet/testdata/cgo/cgo4.go b/libgo/go/cmd/vet/testdata/cgo/cgo4.go
deleted file mode 100644
index 67b54506aba..00000000000
--- a/libgo/go/cmd/vet/testdata/cgo/cgo4.go
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2017 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Test the cgo checker on a file that doesn't use cgo, but has an
-// import named "C".
-
-package testdata
-
-import C "fmt"
-
-var _ = C.Println(*p(**p))
-
-// Passing a pointer (via a slice), but C is fmt, not cgo.
-var _ = C.Println([]int{3})
diff --git a/libgo/go/cmd/vet/testdata/composite.go b/libgo/go/cmd/vet/testdata/composite.go
deleted file mode 100644
index 3fe3eac78cb..00000000000
--- a/libgo/go/cmd/vet/testdata/composite.go
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file contains the test for untagged struct literals.
-
-package testdata
-
-import (
- "flag"
- "go/scanner"
- "image"
- "unicode"
-
- "path/to/unknownpkg"
-)
-
-var Okay1 = []string{
- "Name",
- "Usage",
- "DefValue",
-}
-
-var Okay2 = map[string]bool{
- "Name": true,
- "Usage": true,
- "DefValue": true,
-}
-
-var Okay3 = struct {
- X string
- Y string
- Z string
-}{
- "Name",
- "Usage",
- "DefValue",
-}
-
-var Okay4 = []struct {
- A int
- B int
-}{
- {1, 2},
- {3, 4},
-}
-
-type MyStruct struct {
- X string
- Y string
- Z string
-}
-
-var Okay5 = &MyStruct{
- "Name",
- "Usage",
- "DefValue",
-}
-
-var Okay6 = []MyStruct{
- {"foo", "bar", "baz"},
- {"aa", "bb", "cc"},
-}
-
-var Okay7 = []*MyStruct{
- {"foo", "bar", "baz"},
- {"aa", "bb", "cc"},
-}
-
-// Testing is awkward because we need to reference things from a separate package
-// to trigger the warnings.
-
-var goodStructLiteral = flag.Flag{
- Name: "Name",
- Usage: "Usage",
-}
-var badStructLiteral = flag.Flag{ // ERROR "unkeyed fields"
- "Name",
- "Usage",
- nil, // Value
- "DefValue",
-}
-
-// SpecialCase is a named slice of CaseRange to test issue 9171.
-var goodNamedSliceLiteral = unicode.SpecialCase{
- {Lo: 1, Hi: 2},
- unicode.CaseRange{Lo: 1, Hi: 2},
-}
-var badNamedSliceLiteral = unicode.SpecialCase{
- {1, 2}, // ERROR "unkeyed fields"
- unicode.CaseRange{1, 2}, // ERROR "unkeyed fields"
-}
-
-// ErrorList is a named slice, so no warnings should be emitted.
-var goodScannerErrorList = scanner.ErrorList{
- &scanner.Error{Msg: "foobar"},
-}
-var badScannerErrorList = scanner.ErrorList{
- &scanner.Error{"foobar"}, // ERROR "unkeyed fields"
-}
-
-// Check whitelisted structs: if vet is run with --compositewhitelist=false,
-// this line triggers an error.
-var whitelistedPoint = image.Point{1, 2}
-
-// Do not check type from unknown package.
-// See issue 15408.
-var unknownPkgVar = unknownpkg.Foobar{"foo", "bar"}
-
-// A named pointer slice of CaseRange to test issue 23539. In
-// particular, we're interested in how some slice elements omit their
-// type.
-var goodNamedPointerSliceLiteral = []*unicode.CaseRange{
- {Lo: 1, Hi: 2},
- &unicode.CaseRange{Lo: 1, Hi: 2},
-}
-var badNamedPointerSliceLiteral = []*unicode.CaseRange{
- {1, 2}, // ERROR "unkeyed fields"
- &unicode.CaseRange{1, 2}, // ERROR "unkeyed fields"
-}
diff --git a/libgo/go/cmd/vet/testdata/copylock.go b/libgo/go/cmd/vet/testdata/copylock.go
deleted file mode 100644
index e9902a27f10..00000000000
--- a/libgo/go/cmd/vet/testdata/copylock.go
+++ /dev/null
@@ -1,188 +0,0 @@
-package testdata
-
-import (
- "sync"
- "sync/atomic"
- "unsafe"
- . "unsafe"
- unsafe1 "unsafe"
-)
-
-func OkFunc() {
- var x *sync.Mutex
- p := x
- var y sync.Mutex
- p = &y
-
- var z = sync.Mutex{}
- w := sync.Mutex{}
-
- w = sync.Mutex{}
- q := struct{ L sync.Mutex }{
- L: sync.Mutex{},
- }
-
- yy := []Tlock{
- Tlock{},
- Tlock{
- once: sync.Once{},
- },
- }
-
- nl := new(sync.Mutex)
- mx := make([]sync.Mutex, 10)
- xx := struct{ L *sync.Mutex }{
- L: new(sync.Mutex),
- }
-}
-
-type Tlock struct {
- once sync.Once
-}
-
-func BadFunc() {
- var x *sync.Mutex
- p := x
- var y sync.Mutex
- p = &y
- *p = *x // ERROR "assignment copies lock value to \*p: sync.Mutex"
-
- var t Tlock
- var tp *Tlock
- tp = &t
- *tp = t // ERROR "assignment copies lock value to \*tp: testdata.Tlock contains sync.Once contains sync.Mutex"
- t = *tp // ERROR "assignment copies lock value to t: testdata.Tlock contains sync.Once contains sync.Mutex"
-
- y := *x // ERROR "assignment copies lock value to y: sync.Mutex"
- var z = t // ERROR "variable declaration copies lock value to z: testdata.Tlock contains sync.Once contains sync.Mutex"
-
- w := struct{ L sync.Mutex }{
- L: *x, // ERROR "literal copies lock value from \*x: sync.Mutex"
- }
- var q = map[int]Tlock{
- 1: t, // ERROR "literal copies lock value from t: testdata.Tlock contains sync.Once contains sync.Mutex"
- 2: *tp, // ERROR "literal copies lock value from \*tp: testdata.Tlock contains sync.Once contains sync.Mutex"
- }
- yy := []Tlock{
- t, // ERROR "literal copies lock value from t: testdata.Tlock contains sync.Once contains sync.Mutex"
- *tp, // ERROR "literal copies lock value from \*tp: testdata.Tlock contains sync.Once contains sync.Mutex"
- }
-
- // override 'new' keyword
- new := func(interface{}) {}
- new(t) // ERROR "call of new copies lock value: testdata.Tlock contains sync.Once contains sync.Mutex"
-
- // copy of array of locks
- var muA [5]sync.Mutex
- muB := muA // ERROR "assignment copies lock value to muB: sync.Mutex"
- muA = muB // ERROR "assignment copies lock value to muA: sync.Mutex"
- muSlice := muA[:] // OK
-
- // multidimensional array
- var mmuA [5][5]sync.Mutex
- mmuB := mmuA // ERROR "assignment copies lock value to mmuB: sync.Mutex"
- mmuA = mmuB // ERROR "assignment copies lock value to mmuA: sync.Mutex"
- mmuSlice := mmuA[:] // OK
-
- // slice copy is ok
- var fmuA [5][][5]sync.Mutex
- fmuB := fmuA // OK
- fmuA = fmuB // OK
- fmuSlice := fmuA[:] // OK
-}
-
-func LenAndCapOnLockArrays() {
- var a [5]sync.Mutex
- aLen := len(a) // OK
- aCap := cap(a) // OK
-
- // override 'len' and 'cap' keywords
-
- len := func(interface{}) {}
- len(a) // ERROR "call of len copies lock value: sync.Mutex"
-
- cap := func(interface{}) {}
- cap(a) // ERROR "call of cap copies lock value: sync.Mutex"
-}
-
-func SizeofMutex() {
- var mu sync.Mutex
- unsafe.Sizeof(mu) // OK
- unsafe1.Sizeof(mu) // OK
- Sizeof(mu) // OK
- unsafe := struct{ Sizeof func(interface{}) }{}
- unsafe.Sizeof(mu) // ERROR "call of unsafe.Sizeof copies lock value: sync.Mutex"
- Sizeof := func(interface{}) {}
- Sizeof(mu) // ERROR "call of Sizeof copies lock value: sync.Mutex"
-}
-
-// SyncTypesCheck checks copying of sync.* types except sync.Mutex
-func SyncTypesCheck() {
- // sync.RWMutex copying
- var rwmuX sync.RWMutex
- var rwmuXX = sync.RWMutex{}
- rwmuX1 := new(sync.RWMutex)
- rwmuY := rwmuX // ERROR "assignment copies lock value to rwmuY: sync.RWMutex"
- rwmuY = rwmuX // ERROR "assignment copies lock value to rwmuY: sync.RWMutex"
- var rwmuYY = rwmuX // ERROR "variable declaration copies lock value to rwmuYY: sync.RWMutex"
- rwmuP := &rwmuX
- rwmuZ := &sync.RWMutex{}
-
- // sync.Cond copying
- var condX sync.Cond
- var condXX = sync.Cond{}
- condX1 := new(sync.Cond)
- condY := condX // ERROR "assignment copies lock value to condY: sync.Cond contains sync.noCopy"
- condY = condX // ERROR "assignment copies lock value to condY: sync.Cond contains sync.noCopy"
- var condYY = condX // ERROR "variable declaration copies lock value to condYY: sync.Cond contains sync.noCopy"
- condP := &condX
- condZ := &sync.Cond{
- L: &sync.Mutex{},
- }
- condZ = sync.NewCond(&sync.Mutex{})
-
- // sync.WaitGroup copying
- var wgX sync.WaitGroup
- var wgXX = sync.WaitGroup{}
- wgX1 := new(sync.WaitGroup)
- wgY := wgX // ERROR "assignment copies lock value to wgY: sync.WaitGroup contains sync.noCopy"
- wgY = wgX // ERROR "assignment copies lock value to wgY: sync.WaitGroup contains sync.noCopy"
- var wgYY = wgX // ERROR "variable declaration copies lock value to wgYY: sync.WaitGroup contains sync.noCopy"
- wgP := &wgX
- wgZ := &sync.WaitGroup{}
-
- // sync.Pool copying
- var poolX sync.Pool
- var poolXX = sync.Pool{}
- poolX1 := new(sync.Pool)
- poolY := poolX // ERROR "assignment copies lock value to poolY: sync.Pool contains sync.noCopy"
- poolY = poolX // ERROR "assignment copies lock value to poolY: sync.Pool contains sync.noCopy"
- var poolYY = poolX // ERROR "variable declaration copies lock value to poolYY: sync.Pool contains sync.noCopy"
- poolP := &poolX
- poolZ := &sync.Pool{}
-
- // sync.Once copying
- var onceX sync.Once
- var onceXX = sync.Once{}
- onceX1 := new(sync.Once)
- onceY := onceX // ERROR "assignment copies lock value to onceY: sync.Once contains sync.Mutex"
- onceY = onceX // ERROR "assignment copies lock value to onceY: sync.Once contains sync.Mutex"
- var onceYY = onceX // ERROR "variable declaration copies lock value to onceYY: sync.Once contains sync.Mutex"
- onceP := &onceX
- onceZ := &sync.Once{}
-}
-
-// AtomicTypesCheck checks copying of sync/atomic types
-func AtomicTypesCheck() {
- // atomic.Value copying
- var vX atomic.Value
- var vXX = atomic.Value{}
- vX1 := new(atomic.Value)
- // These are OK because the value has not been used yet.
- // (And vet can't tell whether it has been used, so they're always OK.)
- vY := vX
- vY = vX
- var vYY = vX
- vP := &vX
- vZ := &atomic.Value{}
-}
diff --git a/libgo/go/cmd/vet/testdata/copylock_func.go b/libgo/go/cmd/vet/testdata/copylock_func.go
deleted file mode 100644
index 280747a3bf4..00000000000
--- a/libgo/go/cmd/vet/testdata/copylock_func.go
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file contains tests for the copylock checker's
-// function declaration analysis.
-
-package testdata
-
-import "sync"
-
-func OkFunc(*sync.Mutex) {}
-func BadFunc(sync.Mutex) {} // ERROR "BadFunc passes lock by value: sync.Mutex"
-func BadFunc2(sync.Map) {} // ERROR "BadFunc2 passes lock by value: sync.Map contains sync.Mutex"
-func OkRet() *sync.Mutex {}
-func BadRet() sync.Mutex {} // Don't warn about results
-
-var (
- OkClosure = func(*sync.Mutex) {}
- BadClosure = func(sync.Mutex) {} // ERROR "func passes lock by value: sync.Mutex"
- BadClosure2 = func(sync.Map) {} // ERROR "func passes lock by value: sync.Map contains sync.Mutex"
-)
-
-type EmbeddedRWMutex struct {
- sync.RWMutex
-}
-
-func (*EmbeddedRWMutex) OkMeth() {}
-func (EmbeddedRWMutex) BadMeth() {} // ERROR "BadMeth passes lock by value: testdata.EmbeddedRWMutex"
-func OkFunc(e *EmbeddedRWMutex) {}
-func BadFunc(EmbeddedRWMutex) {} // ERROR "BadFunc passes lock by value: testdata.EmbeddedRWMutex"
-func OkRet() *EmbeddedRWMutex {}
-func BadRet() EmbeddedRWMutex {} // Don't warn about results
-
-type FieldMutex struct {
- s sync.Mutex
-}
-
-func (*FieldMutex) OkMeth() {}
-func (FieldMutex) BadMeth() {} // ERROR "BadMeth passes lock by value: testdata.FieldMutex contains sync.Mutex"
-func OkFunc(*FieldMutex) {}
-func BadFunc(FieldMutex, int) {} // ERROR "BadFunc passes lock by value: testdata.FieldMutex contains sync.Mutex"
-
-type L0 struct {
- L1
-}
-
-type L1 struct {
- l L2
-}
-
-type L2 struct {
- sync.Mutex
-}
-
-func (*L0) Ok() {}
-func (L0) Bad() {} // ERROR "Bad passes lock by value: testdata.L0 contains testdata.L1 contains testdata.L2"
-
-type EmbeddedMutexPointer struct {
- s *sync.Mutex // safe to copy this pointer
-}
-
-func (*EmbeddedMutexPointer) Ok() {}
-func (EmbeddedMutexPointer) AlsoOk() {}
-func StillOk(EmbeddedMutexPointer) {}
-func LookinGood() EmbeddedMutexPointer {}
-
-type EmbeddedLocker struct {
- sync.Locker // safe to copy interface values
-}
-
-func (*EmbeddedLocker) Ok() {}
-func (EmbeddedLocker) AlsoOk() {}
-
-type CustomLock struct{}
-
-func (*CustomLock) Lock() {}
-func (*CustomLock) Unlock() {}
-
-func Ok(*CustomLock) {}
-func Bad(CustomLock) {} // ERROR "Bad passes lock by value: testdata.CustomLock"
-
-// Passing lock values into interface function arguments
-func FuncCallInterfaceArg(f func(a int, b interface{})) {
- var m sync.Mutex
- var t struct{ lock sync.Mutex }
-
- f(1, "foo")
- f(2, &t)
- f(3, &sync.Mutex{})
- f(4, m) // ERROR "call of f copies lock value: sync.Mutex"
- f(5, t) // ERROR "call of f copies lock value: struct.lock sync.Mutex. contains sync.Mutex"
- var fntab []func(t)
- fntab[0](t) // ERROR "call of fntab.0. copies lock value: struct.lock sync.Mutex. contains sync.Mutex"
-}
-
-// Returning lock via interface value
-func ReturnViaInterface(x int) (int, interface{}) {
- var m sync.Mutex
- var t struct{ lock sync.Mutex }
-
- switch x % 4 {
- case 0:
- return 0, "qwe"
- case 1:
- return 1, &sync.Mutex{}
- case 2:
- return 2, m // ERROR "return copies lock value: sync.Mutex"
- default:
- return 3, t // ERROR "return copies lock value: struct.lock sync.Mutex. contains sync.Mutex"
- }
-}
-
-// Some cases that we don't warn about.
-
-func AcceptedCases() {
- x := EmbeddedRwMutex{} // composite literal on RHS is OK (#16227)
- x = BadRet() // function call on RHS is OK (#16227)
- x = *OKRet() // indirection of function call on RHS is OK (#16227)
-}
-
-// TODO: Unfortunate cases
-
-// Non-ideal error message:
-// Since we're looking for Lock methods, sync.Once's underlying
-// sync.Mutex gets called out, but without any reference to the sync.Once.
-type LocalOnce sync.Once
-
-func (LocalOnce) Bad() {} // ERROR "Bad passes lock by value: testdata.LocalOnce contains sync.Mutex"
-
-// False negative:
-// LocalMutex doesn't have a Lock method.
-// Nevertheless, it is probably a bad idea to pass it by value.
-type LocalMutex sync.Mutex
-
-func (LocalMutex) Bad() {} // WANTED: An error here :(
diff --git a/libgo/go/cmd/vet/testdata/copylock_range.go b/libgo/go/cmd/vet/testdata/copylock_range.go
deleted file mode 100644
index f127381213c..00000000000
--- a/libgo/go/cmd/vet/testdata/copylock_range.go
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file contains tests for the copylock checker's
-// range statement analysis.
-
-package testdata
-
-import "sync"
-
-func rangeMutex() {
- var mu sync.Mutex
- var i int
-
- var s []sync.Mutex
- for range s {
- }
- for i = range s {
- }
- for i := range s {
- }
- for i, _ = range s {
- }
- for i, _ := range s {
- }
- for _, mu = range s { // ERROR "range var mu copies lock: sync.Mutex"
- }
- for _, m := range s { // ERROR "range var m copies lock: sync.Mutex"
- }
- for i, mu = range s { // ERROR "range var mu copies lock: sync.Mutex"
- }
- for i, m := range s { // ERROR "range var m copies lock: sync.Mutex"
- }
-
- var a [3]sync.Mutex
- for _, m := range a { // ERROR "range var m copies lock: sync.Mutex"
- }
-
- var m map[sync.Mutex]sync.Mutex
- for k := range m { // ERROR "range var k copies lock: sync.Mutex"
- }
- for mu, _ = range m { // ERROR "range var mu copies lock: sync.Mutex"
- }
- for k, _ := range m { // ERROR "range var k copies lock: sync.Mutex"
- }
- for _, mu = range m { // ERROR "range var mu copies lock: sync.Mutex"
- }
- for _, v := range m { // ERROR "range var v copies lock: sync.Mutex"
- }
-
- var c chan sync.Mutex
- for range c {
- }
- for mu = range c { // ERROR "range var mu copies lock: sync.Mutex"
- }
- for v := range c { // ERROR "range var v copies lock: sync.Mutex"
- }
-
- // Test non-idents in range variables
- var t struct {
- i int
- mu sync.Mutex
- }
- for t.i, t.mu = range s { // ERROR "range var t.mu copies lock: sync.Mutex"
- }
-}
diff --git a/libgo/go/cmd/vet/testdata/deadcode.go b/libgo/go/cmd/vet/testdata/deadcode.go
deleted file mode 100644
index d1a7adee38d..00000000000
--- a/libgo/go/cmd/vet/testdata/deadcode.go
+++ /dev/null
@@ -1,2134 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-// This file contains tests for the dead code checker.
-
-package testdata
-
-type T int
-
-var x interface{}
-var c chan int
-
-func external() int // ok
-
-func _() int {
-}
-
-func _() int {
- print(1)
-}
-
-func _() int {
- print(1)
- return 2
- println() // ERROR "unreachable code"
-}
-
-func _() int {
-L:
- print(1)
- goto L
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- panic(2)
- println() // ERROR "unreachable code"
-}
-
-// but only builtin panic
-func _() int {
- var panic = func(int) {}
- print(1)
- panic(2)
- println() // ok
-}
-
-func _() int {
- {
- print(1)
- return 2
- println() // ERROR "unreachable code"
- }
- println() // ok
-}
-
-func _() int {
- {
- print(1)
- return 2
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
-L:
- {
- print(1)
- goto L
- println() // ERROR "unreachable code"
- }
- println() // ok
-}
-
-func _() int {
-L:
- {
- print(1)
- goto L
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- {
- panic(2)
- }
-}
-
-func _() int {
- print(1)
- {
- panic(2)
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
- print(1)
- {
- panic(2)
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- return 2
- { // ERROR "unreachable code"
- }
-}
-
-func _() int {
-L:
- print(1)
- goto L
- { // ERROR "unreachable code"
- }
-}
-
-func _() int {
- print(1)
- panic(2)
- { // ERROR "unreachable code"
- }
-}
-
-func _() int {
- {
- print(1)
- return 2
- { // ERROR "unreachable code"
- }
- }
-}
-
-func _() int {
-L:
- {
- print(1)
- goto L
- { // ERROR "unreachable code"
- }
- }
-}
-
-func _() int {
- print(1)
- {
- panic(2)
- { // ERROR "unreachable code"
- }
- }
-}
-
-func _() int {
- {
- print(1)
- return 2
- }
- { // ERROR "unreachable code"
- }
-}
-
-func _() int {
-L:
- {
- print(1)
- goto L
- }
- { // ERROR "unreachable code"
- }
-}
-
-func _() int {
- print(1)
- {
- panic(2)
- }
- { // ERROR "unreachable code"
- }
-}
-
-func _() int {
- print(1)
- if x == nil {
- panic(2)
- } else {
- panic(3)
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
-L:
- print(1)
- if x == nil {
- panic(2)
- } else {
- goto L
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
-L:
- print(1)
- if x == nil {
- panic(2)
- } else if x == 1 {
- return 0
- } else if x != 2 {
- panic(3)
- } else {
- goto L
- }
- println() // ERROR "unreachable code"
-}
-
-// if-else chain missing final else is not okay, even if the
-// conditions cover every possible case.
-
-func _() int {
- print(1)
- if x == nil {
- panic(2)
- } else if x != nil {
- panic(3)
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- if x == nil {
- panic(2)
- }
- println() // ok
-}
-
-func _() int {
-L:
- print(1)
- if x == nil {
- panic(2)
- } else if x == 1 {
- return 0
- } else if x != 1 {
- panic(3)
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- for {
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- for {
- for {
- break
- }
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- for {
- for {
- break
- println() // ERROR "unreachable code"
- }
- }
-}
-
-func _() int {
- for {
- for {
- continue
- println() // ERROR "unreachable code"
- }
- }
-}
-
-func _() int {
- for {
- L:
- for {
- break L
- }
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- for {
- break
- }
- println() // ok
-}
-
-func _() int {
- for {
- for {
- }
- break // ERROR "unreachable code"
- }
- println() // ok
-}
-
-func _() int {
-L:
- for {
- for {
- break L
- }
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- for x == nil {
- }
- println() // ok
-}
-
-func _() int {
- for x == nil {
- for {
- break
- }
- }
- println() // ok
-}
-
-func _() int {
- for x == nil {
- L:
- for {
- break L
- }
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- for true {
- }
- println() // ok
-}
-
-func _() int {
- for true {
- for {
- break
- }
- }
- println() // ok
-}
-
-func _() int {
- for true {
- L:
- for {
- break L
- }
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- select {}
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- select {
- case <-c:
- print(2)
- for {
- }
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
- print(1)
- select {
- case <-c:
- print(2)
- for {
- }
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
-L:
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- println() // ERROR "unreachable code"
- case c <- 1:
- print(2)
- goto L
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
-L:
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- case c <- 1:
- print(2)
- goto L
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- println() // ERROR "unreachable code"
- default:
- select {}
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- default:
- select {}
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- select {
- case <-c:
- print(2)
- }
- println() // ok
-}
-
-func _() int {
-L:
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- goto L // ERROR "unreachable code"
- case c <- 1:
- print(2)
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- default:
- print(2)
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- select {
- default:
- break
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- break // ERROR "unreachable code"
- }
- println() // ok
-}
-
-func _() int {
- print(1)
-L:
- select {
- case <-c:
- print(2)
- for {
- break L
- }
- }
- println() // ok
-}
-
-func _() int {
- print(1)
-L:
- select {
- case <-c:
- print(2)
- panic("abc")
- case c <- 1:
- print(2)
- break L
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- select {
- case <-c:
- print(1)
- panic("abc")
- default:
- select {}
- break // ERROR "unreachable code"
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- switch x {
- case 1:
- print(2)
- panic(3)
- println() // ERROR "unreachable code"
- default:
- return 4
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
- print(1)
- switch x {
- case 1:
- print(2)
- panic(3)
- default:
- return 4
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- switch x {
- default:
- return 4
- println() // ERROR "unreachable code"
- case 1:
- print(2)
- panic(3)
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
- print(1)
- switch x {
- default:
- return 4
- case 1:
- print(2)
- panic(3)
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- switch x {
- case 1:
- print(2)
- fallthrough
- default:
- return 4
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
- print(1)
- switch x {
- case 1:
- print(2)
- fallthrough
- default:
- return 4
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- switch {
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- switch x {
- case 1:
- print(2)
- panic(3)
- case 2:
- return 4
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- switch x {
- case 2:
- return 4
- case 1:
- print(2)
- panic(3)
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- switch x {
- case 1:
- print(2)
- fallthrough
- case 2:
- return 4
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- switch x {
- case 1:
- print(2)
- panic(3)
- }
- println() // ok
-}
-
-func _() int {
- print(1)
-L:
- switch x {
- case 1:
- print(2)
- panic(3)
- break L // ERROR "unreachable code"
- default:
- return 4
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- switch x {
- default:
- return 4
- break // ERROR "unreachable code"
- case 1:
- print(2)
- panic(3)
- }
- println() // ok
-}
-
-func _() int {
- print(1)
-L:
- switch x {
- case 1:
- print(2)
- for {
- break L
- }
- default:
- return 4
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- panic(3)
- println() // ERROR "unreachable code"
- default:
- return 4
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- panic(3)
- default:
- return 4
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- switch x.(type) {
- default:
- return 4
- println() // ERROR "unreachable code"
- case int:
- print(2)
- panic(3)
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
- print(1)
- switch x.(type) {
- default:
- return 4
- case int:
- print(2)
- panic(3)
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- fallthrough
- default:
- return 4
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- fallthrough
- default:
- return 4
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- switch {
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- panic(3)
- case float64:
- return 4
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- switch x.(type) {
- case float64:
- return 4
- case int:
- print(2)
- panic(3)
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- fallthrough
- case float64:
- return 4
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- panic(3)
- }
- println() // ok
-}
-
-func _() int {
- print(1)
-L:
- switch x.(type) {
- case int:
- print(2)
- panic(3)
- break L // ERROR "unreachable code"
- default:
- return 4
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- switch x.(type) {
- default:
- return 4
- break // ERROR "unreachable code"
- case int:
- print(2)
- panic(3)
- }
- println() // ok
-}
-
-func _() int {
- print(1)
-L:
- switch x.(type) {
- case int:
- print(2)
- for {
- break L
- }
- default:
- return 4
- }
- println() // ok
-}
-
-// again, but without the leading print(1).
-// testing that everything works when the terminating statement is first.
-
-func _() int {
- println() // ok
-}
-
-func _() int {
- return 2
- println() // ERROR "unreachable code"
-}
-
-func _() int {
-L:
- goto L
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- panic(2)
- println() // ERROR "unreachable code"
-}
-
-// but only builtin panic
-func _() int {
- var panic = func(int) {}
- panic(2)
- println() // ok
-}
-
-func _() int {
- {
- return 2
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
- {
- return 2
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
-L:
- {
- goto L
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
-L:
- {
- goto L
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- {
- panic(2)
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
- {
- panic(2)
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- return 2
- { // ERROR "unreachable code"
- }
- println() // ok
-}
-
-func _() int {
-L:
- goto L
- { // ERROR "unreachable code"
- }
- println() // ok
-}
-
-func _() int {
- panic(2)
- { // ERROR "unreachable code"
- }
- println() // ok
-}
-
-func _() int {
- {
- return 2
- { // ERROR "unreachable code"
- }
- }
- println() // ok
-}
-
-func _() int {
-L:
- {
- goto L
- { // ERROR "unreachable code"
- }
- }
- println() // ok
-}
-
-func _() int {
- {
- panic(2)
- { // ERROR "unreachable code"
- }
- }
- println() // ok
-}
-
-func _() int {
- {
- return 2
- }
- { // ERROR "unreachable code"
- }
- println() // ok
-}
-
-func _() int {
-L:
- {
- goto L
- }
- { // ERROR "unreachable code"
- }
- println() // ok
-}
-
-func _() int {
- {
- panic(2)
- }
- { // ERROR "unreachable code"
- }
- println() // ok
-}
-
-// again, with func literals
-
-var _ = func() int {
-}
-
-var _ = func() int {
- print(1)
-}
-
-var _ = func() int {
- print(1)
- return 2
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
-L:
- print(1)
- goto L
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- panic(2)
- println() // ERROR "unreachable code"
-}
-
-// but only builtin panic
-var _ = func() int {
- var panic = func(int) {}
- print(1)
- panic(2)
- println() // ok
-}
-
-var _ = func() int {
- {
- print(1)
- return 2
- println() // ERROR "unreachable code"
- }
- println() // ok
-}
-
-var _ = func() int {
- {
- print(1)
- return 2
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
-L:
- {
- print(1)
- goto L
- println() // ERROR "unreachable code"
- }
- println() // ok
-}
-
-var _ = func() int {
-L:
- {
- print(1)
- goto L
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- {
- panic(2)
- }
-}
-
-var _ = func() int {
- print(1)
- {
- panic(2)
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- print(1)
- {
- panic(2)
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- return 2
- { // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
-L:
- print(1)
- goto L
- { // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- print(1)
- panic(2)
- { // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- {
- print(1)
- return 2
- { // ERROR "unreachable code"
- }
- }
-}
-
-var _ = func() int {
-L:
- {
- print(1)
- goto L
- { // ERROR "unreachable code"
- }
- }
-}
-
-var _ = func() int {
- print(1)
- {
- panic(2)
- { // ERROR "unreachable code"
- }
- }
-}
-
-var _ = func() int {
- {
- print(1)
- return 2
- }
- { // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
-L:
- {
- print(1)
- goto L
- }
- { // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- print(1)
- {
- panic(2)
- }
- { // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- print(1)
- if x == nil {
- panic(2)
- } else {
- panic(3)
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
-L:
- print(1)
- if x == nil {
- panic(2)
- } else {
- goto L
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
-L:
- print(1)
- if x == nil {
- panic(2)
- } else if x == 1 {
- return 0
- } else if x != 2 {
- panic(3)
- } else {
- goto L
- }
- println() // ERROR "unreachable code"
-}
-
-// if-else chain missing final else is not okay, even if the
-// conditions cover every possible case.
-
-var _ = func() int {
- print(1)
- if x == nil {
- panic(2)
- } else if x != nil {
- panic(3)
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- if x == nil {
- panic(2)
- }
- println() // ok
-}
-
-var _ = func() int {
-L:
- print(1)
- if x == nil {
- panic(2)
- } else if x == 1 {
- return 0
- } else if x != 1 {
- panic(3)
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- for {
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- for {
- for {
- break
- }
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- for {
- for {
- break
- println() // ERROR "unreachable code"
- }
- }
-}
-
-var _ = func() int {
- for {
- for {
- continue
- println() // ERROR "unreachable code"
- }
- }
-}
-
-var _ = func() int {
- for {
- L:
- for {
- break L
- }
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- for {
- break
- }
- println() // ok
-}
-
-var _ = func() int {
- for {
- for {
- }
- break // ERROR "unreachable code"
- }
- println() // ok
-}
-
-var _ = func() int {
-L:
- for {
- for {
- break L
- }
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- for x == nil {
- }
- println() // ok
-}
-
-var _ = func() int {
- for x == nil {
- for {
- break
- }
- }
- println() // ok
-}
-
-var _ = func() int {
- for x == nil {
- L:
- for {
- break L
- }
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- for true {
- }
- println() // ok
-}
-
-var _ = func() int {
- for true {
- for {
- break
- }
- }
- println() // ok
-}
-
-var _ = func() int {
- for true {
- L:
- for {
- break L
- }
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- select {}
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- select {
- case <-c:
- print(2)
- for {
- }
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- print(1)
- select {
- case <-c:
- print(2)
- for {
- }
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
-L:
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- println() // ERROR "unreachable code"
- case c <- 1:
- print(2)
- goto L
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
-L:
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- case c <- 1:
- print(2)
- goto L
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- println() // ERROR "unreachable code"
- default:
- select {}
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- default:
- select {}
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- select {
- case <-c:
- print(2)
- }
- println() // ok
-}
-
-var _ = func() int {
-L:
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- goto L // ERROR "unreachable code"
- case c <- 1:
- print(2)
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- default:
- print(2)
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- select {
- default:
- break
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- break // ERROR "unreachable code"
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
-L:
- select {
- case <-c:
- print(2)
- for {
- break L
- }
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
-L:
- select {
- case <-c:
- print(2)
- panic("abc")
- case c <- 1:
- print(2)
- break L
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- select {
- case <-c:
- print(1)
- panic("abc")
- default:
- select {}
- break // ERROR "unreachable code"
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- switch x {
- case 1:
- print(2)
- panic(3)
- println() // ERROR "unreachable code"
- default:
- return 4
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- print(1)
- switch x {
- case 1:
- print(2)
- panic(3)
- default:
- return 4
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- switch x {
- default:
- return 4
- println() // ERROR "unreachable code"
- case 1:
- print(2)
- panic(3)
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- print(1)
- switch x {
- default:
- return 4
- case 1:
- print(2)
- panic(3)
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- switch x {
- case 1:
- print(2)
- fallthrough
- default:
- return 4
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- print(1)
- switch x {
- case 1:
- print(2)
- fallthrough
- default:
- return 4
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- switch {
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- switch x {
- case 1:
- print(2)
- panic(3)
- case 2:
- return 4
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- switch x {
- case 2:
- return 4
- case 1:
- print(2)
- panic(3)
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- switch x {
- case 1:
- print(2)
- fallthrough
- case 2:
- return 4
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- switch x {
- case 1:
- print(2)
- panic(3)
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
-L:
- switch x {
- case 1:
- print(2)
- panic(3)
- break L // ERROR "unreachable code"
- default:
- return 4
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- switch x {
- default:
- return 4
- break // ERROR "unreachable code"
- case 1:
- print(2)
- panic(3)
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
-L:
- switch x {
- case 1:
- print(2)
- for {
- break L
- }
- default:
- return 4
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- panic(3)
- println() // ERROR "unreachable code"
- default:
- return 4
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- panic(3)
- default:
- return 4
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- switch x.(type) {
- default:
- return 4
- println() // ERROR "unreachable code"
- case int:
- print(2)
- panic(3)
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- print(1)
- switch x.(type) {
- default:
- return 4
- case int:
- print(2)
- panic(3)
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- fallthrough
- default:
- return 4
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- fallthrough
- default:
- return 4
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- switch {
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- panic(3)
- case float64:
- return 4
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- switch x.(type) {
- case float64:
- return 4
- case int:
- print(2)
- panic(3)
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- fallthrough
- case float64:
- return 4
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- panic(3)
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
-L:
- switch x.(type) {
- case int:
- print(2)
- panic(3)
- break L // ERROR "unreachable code"
- default:
- return 4
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- switch x.(type) {
- default:
- return 4
- break // ERROR "unreachable code"
- case int:
- print(2)
- panic(3)
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
-L:
- switch x.(type) {
- case int:
- print(2)
- for {
- break L
- }
- default:
- return 4
- }
- println() // ok
-}
-
-// again, but without the leading print(1).
-// testing that everything works when the terminating statement is first.
-
-var _ = func() int {
- println() // ok
-}
-
-var _ = func() int {
- return 2
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
-L:
- goto L
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- panic(2)
- println() // ERROR "unreachable code"
-}
-
-// but only builtin panic
-var _ = func() int {
- var panic = func(int) {}
- panic(2)
- println() // ok
-}
-
-var _ = func() int {
- {
- return 2
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- {
- return 2
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
-L:
- {
- goto L
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
-L:
- {
- goto L
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- {
- panic(2)
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- {
- panic(2)
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- return 2
- { // ERROR "unreachable code"
- }
- println() // ok
-}
-
-var _ = func() int {
-L:
- goto L
- { // ERROR "unreachable code"
- }
- println() // ok
-}
-
-var _ = func() int {
- panic(2)
- { // ERROR "unreachable code"
- }
- println() // ok
-}
-
-var _ = func() int {
- {
- return 2
- { // ERROR "unreachable code"
- }
- }
- println() // ok
-}
-
-var _ = func() int {
-L:
- {
- goto L
- { // ERROR "unreachable code"
- }
- }
- println() // ok
-}
-
-var _ = func() int {
- {
- panic(2)
- { // ERROR "unreachable code"
- }
- }
- println() // ok
-}
-
-var _ = func() int {
- {
- return 2
- }
- { // ERROR "unreachable code"
- }
- println() // ok
-}
-
-var _ = func() int {
-L:
- {
- goto L
- }
- { // ERROR "unreachable code"
- }
- println() // ok
-}
-
-var _ = func() int {
- {
- panic(2)
- }
- { // ERROR "unreachable code"
- }
- println() // ok
-}
-
-var _ = func() {
- // goto without label used to panic
- goto
-}
-
-func _() int {
- // Empty switch tag with non-bool case value used to panic.
- switch {
- case 1:
- println()
- }
- println()
-}
diff --git a/libgo/go/cmd/vet/testdata/divergent/buf.go b/libgo/go/cmd/vet/testdata/divergent/buf.go
deleted file mode 100644
index 0efe0f838d5..00000000000
--- a/libgo/go/cmd/vet/testdata/divergent/buf.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// Test of examples with divergent packages.
-
-// Package buf ...
-package buf
-
-// Buf is a ...
-type Buf []byte
-
-// Append ...
-func (*Buf) Append([]byte) {}
-
-func (Buf) Reset() {}
-
-func (Buf) Len() int { return 0 }
-
-// DefaultBuf is a ...
-var DefaultBuf Buf
diff --git a/libgo/go/cmd/vet/testdata/divergent/buf_test.go b/libgo/go/cmd/vet/testdata/divergent/buf_test.go
deleted file mode 100644
index b75d55eaf4f..00000000000
--- a/libgo/go/cmd/vet/testdata/divergent/buf_test.go
+++ /dev/null
@@ -1,35 +0,0 @@
-// Test of examples with divergent packages.
-
-package buf_test
-
-func Example() {} // OK because is package-level.
-
-func Example_suffix() {} // OK because refers to suffix annotation.
-
-func Example_BadSuffix() {} // ERROR "Example_BadSuffix has malformed example suffix: BadSuffix"
-
-func ExampleBuf() {} // OK because refers to known top-level type.
-
-func ExampleBuf_Append() {} // OK because refers to known method.
-
-func ExampleBuf_Clear() {} // ERROR "ExampleBuf_Clear refers to unknown field or method: Buf.Clear"
-
-func ExampleBuf_suffix() {} // OK because refers to suffix annotation.
-
-func ExampleBuf_Append_Bad() {} // ERROR "ExampleBuf_Append_Bad has malformed example suffix: Bad"
-
-func ExampleBuf_Append_suffix() {} // OK because refers to known method with valid suffix.
-
-func ExampleDefaultBuf() {} // OK because refers to top-level identifier.
-
-func ExampleBuf_Reset() bool { return true } // ERROR "ExampleBuf_Reset should return nothing"
-
-func ExampleBuf_Len(i int) {} // ERROR "ExampleBuf_Len should be niladic"
-
-// "Puffer" is German for "Buffer".
-
-func ExamplePuffer() {} // ERROR "ExamplePuffer refers to unknown identifier: Puffer"
-
-func ExamplePuffer_Append() {} // ERROR "ExamplePuffer_Append refers to unknown identifier: Puffer"
-
-func ExamplePuffer_suffix() {} // ERROR "ExamplePuffer_suffix refers to unknown identifier: Puffer"
diff --git a/libgo/go/cmd/vet/testdata/httpresponse.go b/libgo/go/cmd/vet/testdata/httpresponse.go
deleted file mode 100644
index 7302a64a3b6..00000000000
--- a/libgo/go/cmd/vet/testdata/httpresponse.go
+++ /dev/null
@@ -1,85 +0,0 @@
-package testdata
-
-import (
- "log"
- "net/http"
-)
-
-func goodHTTPGet() {
- res, err := http.Get("http://foo.com")
- if err != nil {
- log.Fatal(err)
- }
- defer res.Body.Close()
-}
-
-func badHTTPGet() {
- res, err := http.Get("http://foo.com")
- defer res.Body.Close() // ERROR "using res before checking for errors"
- if err != nil {
- log.Fatal(err)
- }
-}
-
-func badHTTPHead() {
- res, err := http.Head("http://foo.com")
- defer res.Body.Close() // ERROR "using res before checking for errors"
- if err != nil {
- log.Fatal(err)
- }
-}
-
-func goodClientGet() {
- client := http.DefaultClient
- res, err := client.Get("http://foo.com")
- if err != nil {
- log.Fatal(err)
- }
- defer res.Body.Close()
-}
-
-func badClientPtrGet() {
- client := http.DefaultClient
- resp, err := client.Get("http://foo.com")
- defer resp.Body.Close() // ERROR "using resp before checking for errors"
- if err != nil {
- log.Fatal(err)
- }
-}
-
-func badClientGet() {
- client := http.Client{}
- resp, err := client.Get("http://foo.com")
- defer resp.Body.Close() // ERROR "using resp before checking for errors"
- if err != nil {
- log.Fatal(err)
- }
-}
-
-func badClientPtrDo() {
- client := http.DefaultClient
- req, err := http.NewRequest("GET", "http://foo.com", nil)
- if err != nil {
- log.Fatal(err)
- }
-
- resp, err := client.Do(req)
- defer resp.Body.Close() // ERROR "using resp before checking for errors"
- if err != nil {
- log.Fatal(err)
- }
-}
-
-func badClientDo() {
- var client http.Client
- req, err := http.NewRequest("GET", "http://foo.com", nil)
- if err != nil {
- log.Fatal(err)
- }
-
- resp, err := client.Do(req)
- defer resp.Body.Close() // ERROR "using resp before checking for errors"
- if err != nil {
- log.Fatal(err)
- }
-}
diff --git a/libgo/go/cmd/vet/testdata/incomplete/examples_test.go b/libgo/go/cmd/vet/testdata/incomplete/examples_test.go
deleted file mode 100644
index 445502b39ec..00000000000
--- a/libgo/go/cmd/vet/testdata/incomplete/examples_test.go
+++ /dev/null
@@ -1,33 +0,0 @@
-// Test of examples.
-
-package testdata
-
-func Example() {} // OK because is package-level.
-
-func Example_suffix() // OK because refers to suffix annotation.
-
-func Example_BadSuffix() // OK because non-test package was excluded. No false positives wanted.
-
-func ExampleBuf() // OK because non-test package was excluded. No false positives wanted.
-
-func ExampleBuf_Append() {} // OK because non-test package was excluded. No false positives wanted.
-
-func ExampleBuf_Clear() {} // OK because non-test package was excluded. No false positives wanted.
-
-func ExampleBuf_suffix() {} // OK because refers to suffix annotation.
-
-func ExampleBuf_Append_Bad() {} // OK because non-test package was excluded. No false positives wanted.
-
-func ExampleBuf_Append_suffix() {} // OK because refers to known method with valid suffix.
-
-func ExampleBuf_Reset() bool { return true } // ERROR "ExampleBuf_Reset should return nothing"
-
-func ExampleBuf_Len(i int) {} // ERROR "ExampleBuf_Len should be niladic"
-
-// "Puffer" is German for "Buffer".
-
-func ExamplePuffer() // OK because non-test package was excluded. No false positives wanted.
-
-func ExamplePuffer_Append() // OK because non-test package was excluded. No false positives wanted.
-
-func ExamplePuffer_suffix() // OK because non-test package was excluded. No false positives wanted.
diff --git a/libgo/go/cmd/vet/testdata/lostcancel.go b/libgo/go/cmd/vet/testdata/lostcancel.go
deleted file mode 100644
index b7549c00511..00000000000
--- a/libgo/go/cmd/vet/testdata/lostcancel.go
+++ /dev/null
@@ -1,155 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package testdata
-
-import (
- "context"
- "log"
- "os"
- "testing"
-)
-
-// Check the three functions and assignment forms (var, :=, =) we look for.
-// (Do these early: line numbers are fragile.)
-func _() {
- var ctx, cancel = context.WithCancel() // ERROR "the cancel function is not used on all paths \(possible context leak\)"
-} // ERROR "this return statement may be reached without using the cancel var defined on line 17"
-
-func _() {
- ctx, cancel2 := context.WithDeadline() // ERROR "the cancel2 function is not used..."
-} // ERROR "may be reached without using the cancel2 var defined on line 21"
-
-func _() {
- var ctx context.Context
- var cancel3 func()
- ctx, cancel3 = context.WithTimeout() // ERROR "function is not used..."
-} // ERROR "this return statement may be reached without using the cancel3 var defined on line 27"
-
-func _() {
- ctx, _ := context.WithCancel() // ERROR "the cancel function returned by context.WithCancel should be called, not discarded, to avoid a context leak"
- ctx, _ = context.WithTimeout() // ERROR "the cancel function returned by context.WithTimeout should be called, not discarded, to avoid a context leak"
- ctx, _ = context.WithDeadline() // ERROR "the cancel function returned by context.WithDeadline should be called, not discarded, to avoid a context leak"
-}
-
-func _() {
- ctx, cancel := context.WithCancel()
- defer cancel() // ok
-}
-
-func _() {
- ctx, cancel := context.WithCancel() // ERROR "not used on all paths"
- if condition {
- cancel()
- }
- return // ERROR "this return statement may be reached without using the cancel var"
-}
-
-func _() {
- ctx, cancel := context.WithCancel()
- if condition {
- cancel()
- } else {
- // ok: infinite loop
- for {
- print(0)
- }
- }
-}
-
-func _() {
- ctx, cancel := context.WithCancel() // ERROR "not used on all paths"
- if condition {
- cancel()
- } else {
- for i := 0; i < 10; i++ {
- print(0)
- }
- }
-} // ERROR "this return statement may be reached without using the cancel var"
-
-func _() {
- ctx, cancel := context.WithCancel()
- // ok: used on all paths
- switch someInt {
- case 0:
- new(testing.T).FailNow()
- case 1:
- log.Fatal()
- case 2:
- cancel()
- case 3:
- print("hi")
- fallthrough
- default:
- os.Exit(1)
- }
-}
-
-func _() {
- ctx, cancel := context.WithCancel() // ERROR "not used on all paths"
- switch someInt {
- case 0:
- new(testing.T).FailNow()
- case 1:
- log.Fatal()
- case 2:
- cancel()
- case 3:
- print("hi") // falls through to implicit return
- default:
- os.Exit(1)
- }
-} // ERROR "this return statement may be reached without using the cancel var"
-
-func _(ch chan int) int {
- ctx, cancel := context.WithCancel() // ERROR "not used on all paths"
- select {
- case <-ch:
- new(testing.T).FailNow()
- case y <- ch:
- print("hi") // falls through to implicit return
- case ch <- 1:
- cancel()
- default:
- os.Exit(1)
- }
-} // ERROR "this return statement may be reached without using the cancel var"
-
-func _(ch chan int) int {
- ctx, cancel := context.WithCancel()
- // A blocking select must execute one of its cases.
- select {
- case <-ch:
- panic()
- }
-}
-
-func _() {
- go func() {
- ctx, cancel := context.WithCancel() // ERROR "not used on all paths"
- print(ctx)
- }() // ERROR "may be reached without using the cancel var"
-}
-
-var condition bool
-var someInt int
-
-// Regression test for Go issue 16143.
-func _() {
- var x struct{ f func() }
- x.f()
-}
-
-// Regression test for Go issue 16230.
-func _() (ctx context.Context, cancel func()) {
- ctx, cancel = context.WithCancel()
- return // a naked return counts as a load of the named result values
-}
-
-// Same as above, but for literal function.
-var _ = func() (ctx context.Context, cancel func()) {
- ctx, cancel = context.WithCancel()
- return
-}
diff --git a/libgo/go/cmd/vet/testdata/nilfunc.go b/libgo/go/cmd/vet/testdata/nilfunc.go
deleted file mode 100644
index 2ce7bc8ca82..00000000000
--- a/libgo/go/cmd/vet/testdata/nilfunc.go
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package testdata
-
-func F() {}
-
-type T struct {
- F func()
-}
-
-func (T) M() {}
-
-var Fv = F
-
-func Comparison() {
- var t T
- var fn func()
- if fn == nil || Fv == nil || t.F == nil {
- // no error; these func vars or fields may be nil
- }
- if F == nil { // ERROR "comparison of function F == nil is always false"
- panic("can't happen")
- }
- if t.M == nil { // ERROR "comparison of function M == nil is always false"
- panic("can't happen")
- }
- if F != nil { // ERROR "comparison of function F != nil is always true"
- if t.M != nil { // ERROR "comparison of function M != nil is always true"
- return
- }
- }
- panic("can't happen")
-}
diff --git a/libgo/go/cmd/vet/testdata/rangeloop.go b/libgo/go/cmd/vet/testdata/rangeloop.go
deleted file mode 100644
index cd3b4cbc452..00000000000
--- a/libgo/go/cmd/vet/testdata/rangeloop.go
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file contains tests for the rangeloop checker.
-
-package testdata
-
-func RangeLoopTests() {
- var s []int
- for i, v := range s {
- go func() {
- println(i) // ERROR "loop variable i captured by func literal"
- println(v) // ERROR "loop variable v captured by func literal"
- }()
- }
- for i, v := range s {
- defer func() {
- println(i) // ERROR "loop variable i captured by func literal"
- println(v) // ERROR "loop variable v captured by func literal"
- }()
- }
- for i := range s {
- go func() {
- println(i) // ERROR "loop variable i captured by func literal"
- }()
- }
- for _, v := range s {
- go func() {
- println(v) // ERROR "loop variable v captured by func literal"
- }()
- }
- for i, v := range s {
- go func() {
- println(i, v)
- }()
- println("unfortunately, we don't catch the error above because of this statement")
- }
- for i, v := range s {
- go func(i, v int) {
- println(i, v)
- }(i, v)
- }
- for i, v := range s {
- i, v := i, v
- go func() {
- println(i, v)
- }()
- }
- // If the key of the range statement is not an identifier
- // the code should not panic (it used to).
- var x [2]int
- var f int
- for x[0], f = range s {
- go func() {
- _ = f // ERROR "loop variable f captured by func literal"
- }()
- }
- type T struct {
- v int
- }
- for _, v := range s {
- go func() {
- _ = T{v: 1}
- _ = []int{v: 1} // ERROR "loop variable v captured by func literal"
- }()
- }
-
- // ordinary for-loops
- for i := 0; i < 10; i++ {
- go func() {
- print(i) // ERROR "loop variable i captured by func literal"
- }()
- }
- for i, j := 0, 1; i < 100; i, j = j, i+j {
- go func() {
- print(j) // ERROR "loop variable j captured by func literal"
- }()
- }
- type cons struct {
- car int
- cdr *cons
- }
- var head *cons
- for p := head; p != nil; p = p.next {
- go func() {
- print(p.car) // ERROR "loop variable p captured by func literal"
- }()
- }
-}
diff --git a/libgo/go/cmd/vet/testdata/shadow.go b/libgo/go/cmd/vet/testdata/shadow.go
deleted file mode 100644
index c55cb2772a9..00000000000
--- a/libgo/go/cmd/vet/testdata/shadow.go
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file contains tests for the shadowed variable checker.
-// Some of these errors are caught by the compiler (shadowed return parameters for example)
-// but are nonetheless useful tests.
-
-package testdata
-
-import "os"
-
-func ShadowRead(f *os.File, buf []byte) (err error) {
- var x int
- if f != nil {
- err := 3 // OK - different type.
- _ = err
- }
- if f != nil {
- _, err := f.Read(buf) // ERROR "declaration of .err. shadows declaration at shadow.go:13"
- if err != nil {
- return err
- }
- i := 3 // OK
- _ = i
- }
- if f != nil {
- x := one() // ERROR "declaration of .x. shadows declaration at shadow.go:14"
- var _, err = f.Read(buf) // ERROR "declaration of .err. shadows declaration at shadow.go:13"
- if x == 1 && err != nil {
- return err
- }
- }
- for i := 0; i < 10; i++ {
- i := i // OK: obviously intentional idiomatic redeclaration
- go func() {
- println(i)
- }()
- }
- var shadowTemp interface{}
- switch shadowTemp := shadowTemp.(type) { // OK: obviously intentional idiomatic redeclaration
- case int:
- println("OK")
- _ = shadowTemp
- }
- if shadowTemp := shadowTemp; true { // OK: obviously intentional idiomatic redeclaration
- var f *os.File // OK because f is not mentioned later in the function.
- // The declaration of x is a shadow because x is mentioned below.
- var x int // ERROR "declaration of .x. shadows declaration at shadow.go:14"
- _, _, _ = x, f, shadowTemp
- }
- // Use a couple of variables to trigger shadowing errors.
- _, _ = err, x
- return
-}
-
-func one() int {
- return 1
-}
diff --git a/libgo/go/cmd/vet/testdata/shift.go b/libgo/go/cmd/vet/testdata/shift.go
deleted file mode 100644
index 73cbaf88418..00000000000
--- a/libgo/go/cmd/vet/testdata/shift.go
+++ /dev/null
@@ -1,162 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file contains tests for the suspicious shift checker.
-
-package testdata
-
-import (
- "fmt"
- "unsafe"
-)
-
-func ShiftTest() {
- var i8 int8
- _ = i8 << 7
- _ = (i8 + 1) << 8 // ERROR ".i8 . 1. .8 bits. too small for shift of 8"
- _ = i8 << (7 + 1) // ERROR "i8 .8 bits. too small for shift of 8"
- _ = i8 >> 8 // ERROR "i8 .8 bits. too small for shift of 8"
- i8 <<= 8 // ERROR "i8 .8 bits. too small for shift of 8"
- i8 >>= 8 // ERROR "i8 .8 bits. too small for shift of 8"
- var i16 int16
- _ = i16 << 15
- _ = i16 << 16 // ERROR "i16 .16 bits. too small for shift of 16"
- _ = i16 >> 16 // ERROR "i16 .16 bits. too small for shift of 16"
- i16 <<= 16 // ERROR "i16 .16 bits. too small for shift of 16"
- i16 >>= 16 // ERROR "i16 .16 bits. too small for shift of 16"
- var i32 int32
- _ = i32 << 31
- _ = i32 << 32 // ERROR "i32 .32 bits. too small for shift of 32"
- _ = i32 >> 32 // ERROR "i32 .32 bits. too small for shift of 32"
- i32 <<= 32 // ERROR "i32 .32 bits. too small for shift of 32"
- i32 >>= 32 // ERROR "i32 .32 bits. too small for shift of 32"
- var i64 int64
- _ = i64 << 63
- _ = i64 << 64 // ERROR "i64 .64 bits. too small for shift of 64"
- _ = i64 >> 64 // ERROR "i64 .64 bits. too small for shift of 64"
- i64 <<= 64 // ERROR "i64 .64 bits. too small for shift of 64"
- i64 >>= 64 // ERROR "i64 .64 bits. too small for shift of 64"
- var u8 uint8
- _ = u8 << 7
- _ = u8 << 8 // ERROR "u8 .8 bits. too small for shift of 8"
- _ = u8 >> 8 // ERROR "u8 .8 bits. too small for shift of 8"
- u8 <<= 8 // ERROR "u8 .8 bits. too small for shift of 8"
- u8 >>= 8 // ERROR "u8 .8 bits. too small for shift of 8"
- var u16 uint16
- _ = u16 << 15
- _ = u16 << 16 // ERROR "u16 .16 bits. too small for shift of 16"
- _ = u16 >> 16 // ERROR "u16 .16 bits. too small for shift of 16"
- u16 <<= 16 // ERROR "u16 .16 bits. too small for shift of 16"
- u16 >>= 16 // ERROR "u16 .16 bits. too small for shift of 16"
- var u32 uint32
- _ = u32 << 31
- _ = u32 << 32 // ERROR "u32 .32 bits. too small for shift of 32"
- _ = u32 >> 32 // ERROR "u32 .32 bits. too small for shift of 32"
- u32 <<= 32 // ERROR "u32 .32 bits. too small for shift of 32"
- u32 >>= 32 // ERROR "u32 .32 bits. too small for shift of 32"
- var u64 uint64
- _ = u64 << 63
- _ = u64 << 64 // ERROR "u64 .64 bits. too small for shift of 64"
- _ = u64 >> 64 // ERROR "u64 .64 bits. too small for shift of 64"
- u64 <<= 64 // ERROR "u64 .64 bits. too small for shift of 64"
- u64 >>= 64 // ERROR "u64 .64 bits. too small for shift of 64"
- _ = u64 << u64 // Non-constant shifts should succeed.
-
- var i int
- _ = i << 31
- const in = 8 * unsafe.Sizeof(i)
- _ = i << in // ERROR "too small for shift"
- _ = i >> in // ERROR "too small for shift"
- i <<= in // ERROR "too small for shift"
- i >>= in // ERROR "too small for shift"
- const ix = 8*unsafe.Sizeof(i) - 1
- _ = i << ix
- _ = i >> ix
- i <<= ix
- i >>= ix
-
- var u uint
- _ = u << 31
- const un = 8 * unsafe.Sizeof(u)
- _ = u << un // ERROR "too small for shift"
- _ = u >> un // ERROR "too small for shift"
- u <<= un // ERROR "too small for shift"
- u >>= un // ERROR "too small for shift"
- const ux = 8*unsafe.Sizeof(u) - 1
- _ = u << ux
- _ = u >> ux
- u <<= ux
- u >>= ux
-
- var p uintptr
- _ = p << 31
- const pn = 8 * unsafe.Sizeof(p)
- _ = p << pn // ERROR "too small for shift"
- _ = p >> pn // ERROR "too small for shift"
- p <<= pn // ERROR "too small for shift"
- p >>= pn // ERROR "too small for shift"
- const px = 8*unsafe.Sizeof(p) - 1
- _ = p << px
- _ = p >> px
- p <<= px
- p >>= px
-
- const oneIf64Bit = ^uint(0) >> 63 // allow large shifts of constants; they are used for 32/64 bit compatibility tricks
-
- var h uintptr
- h = h<<8 | (h >> (8 * (unsafe.Sizeof(h) - 1)))
- h <<= 8 * unsafe.Sizeof(h) // ERROR "too small for shift"
- h >>= 7 * unsafe.Alignof(h)
- h >>= 8 * unsafe.Alignof(h) // ERROR "too small for shift"
-}
-
-func ShiftDeadCode() {
- var i int
- const iBits = 8 * unsafe.Sizeof(i)
-
- if iBits <= 32 {
- if iBits == 16 {
- _ = i >> 8
- } else {
- _ = i >> 16
- }
- } else {
- _ = i >> 32
- }
-
- if iBits >= 64 {
- _ = i << 32
- if iBits == 128 {
- _ = i << 64
- }
- } else {
- _ = i << 16
- }
-
- if iBits == 64 {
- _ = i << 32
- }
-
- switch iBits {
- case 128, 64:
- _ = i << 32
- default:
- _ = i << 16
- }
-
- switch {
- case iBits < 32:
- _ = i << 16
- case iBits > 64:
- _ = i << 64
- default:
- _ = i << 64 // ERROR "too small for shift"
- }
-
- // Make sure other vet checks work in dead code.
- if iBits == 1024 {
- _ = i << 512 // OK
- fmt.Printf("foo %s bar", 123) // ERROR "Printf"
- }
-}
diff --git a/libgo/go/cmd/vet/testdata/src/asm/asm.go b/libgo/go/cmd/vet/testdata/src/asm/asm.go
new file mode 100644
index 00000000000..72ff452aae8
--- /dev/null
+++ b/libgo/go/cmd/vet/testdata/src/asm/asm.go
@@ -0,0 +1,9 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains declarations to test the assembly in asm1.s.
+
+package testdata
+
+func arg1(x int8, y uint8)
diff --git a/libgo/go/cmd/vet/testdata/src/asm/asm1.s b/libgo/go/cmd/vet/testdata/src/asm/asm1.s
new file mode 100644
index 00000000000..c3ba986fb8b
--- /dev/null
+++ b/libgo/go/cmd/vet/testdata/src/asm/asm1.s
@@ -0,0 +1,8 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build amd64
+
+TEXT ·arg1(SB),0,$0-2
+ MOVW x+0(FP), AX // ERROR "\[amd64\] arg1: invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
diff --git a/libgo/go/cmd/vet/testdata/assign.go b/libgo/go/cmd/vet/testdata/src/assign/assign.go
index 6140ad4db8c..112614e562c 100644
--- a/libgo/go/cmd/vet/testdata/assign.go
+++ b/libgo/go/cmd/vet/testdata/src/assign/assign.go
@@ -4,7 +4,7 @@
// This file contains tests for the useless-assignment checker.
-package testdata
+package assign
import "math/rand"
diff --git a/libgo/go/cmd/vet/testdata/src/atomic/atomic.go b/libgo/go/cmd/vet/testdata/src/atomic/atomic.go
new file mode 100644
index 00000000000..650d56bdada
--- /dev/null
+++ b/libgo/go/cmd/vet/testdata/src/atomic/atomic.go
@@ -0,0 +1,14 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains tests for the atomic checker.
+
+package atomic
+
+import "sync/atomic"
+
+func AtomicTests() {
+ x := uint64(1)
+ x = atomic.AddUint64(&x, 1) // ERROR "direct assignment to atomic value"
+}
diff --git a/libgo/go/cmd/vet/testdata/src/bool/bool.go b/libgo/go/cmd/vet/testdata/src/bool/bool.go
new file mode 100644
index 00000000000..20e01aa46f0
--- /dev/null
+++ b/libgo/go/cmd/vet/testdata/src/bool/bool.go
@@ -0,0 +1,14 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains tests for the bool checker.
+
+package bool
+
+func _() {
+ var f, g func() int
+
+ if v, w := f(), g(); v == w || v == w { // ERROR "redundant or: v == w || v == w"
+ }
+}
diff --git a/libgo/go/cmd/vet/testdata/buildtag/buildtag.go b/libgo/go/cmd/vet/testdata/src/buildtag/buildtag.go
index c2fd6aaaf2f..c2fd6aaaf2f 100644
--- a/libgo/go/cmd/vet/testdata/buildtag/buildtag.go
+++ b/libgo/go/cmd/vet/testdata/src/buildtag/buildtag.go
diff --git a/libgo/go/cmd/vet/testdata/src/cgo/cgo.go b/libgo/go/cmd/vet/testdata/src/cgo/cgo.go
new file mode 100644
index 00000000000..292d7fdab7d
--- /dev/null
+++ b/libgo/go/cmd/vet/testdata/src/cgo/cgo.go
@@ -0,0 +1,18 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains tests for the cgo checker.
+
+package testdata
+
+// void f(void *p) {}
+import "C"
+
+import "unsafe"
+
+func CgoTests() {
+ var c chan bool
+ C.f(*(*unsafe.Pointer)(unsafe.Pointer(&c))) // ERROR "embedded pointer"
+ C.f(unsafe.Pointer(&c)) // ERROR "embedded pointer"
+}
diff --git a/libgo/go/cmd/vet/testdata/src/composite/composite.go b/libgo/go/cmd/vet/testdata/src/composite/composite.go
new file mode 100644
index 00000000000..63a28378515
--- /dev/null
+++ b/libgo/go/cmd/vet/testdata/src/composite/composite.go
@@ -0,0 +1,24 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains the test for untagged struct literals.
+
+package composite
+
+import "flag"
+
+// Testing is awkward because we need to reference things from a separate package
+// to trigger the warnings.
+
+var goodStructLiteral = flag.Flag{
+ Name: "Name",
+ Usage: "Usage",
+}
+
+var badStructLiteral = flag.Flag{ // ERROR "unkeyed fields"
+ "Name",
+ "Usage",
+ nil, // Value
+ "DefValue",
+}
diff --git a/libgo/go/cmd/vet/testdata/src/copylock/copylock.go b/libgo/go/cmd/vet/testdata/src/copylock/copylock.go
new file mode 100644
index 00000000000..8079cf3248b
--- /dev/null
+++ b/libgo/go/cmd/vet/testdata/src/copylock/copylock.go
@@ -0,0 +1,11 @@
+package copylock
+
+import "sync"
+
+func BadFunc() {
+ var x *sync.Mutex
+ p := x
+ var y sync.Mutex
+ p = &y
+ *p = *x // ERROR "assignment copies lock value to \*p: sync.Mutex"
+}
diff --git a/libgo/go/cmd/vet/testdata/src/deadcode/deadcode.go b/libgo/go/cmd/vet/testdata/src/deadcode/deadcode.go
new file mode 100644
index 00000000000..af83cdfbb1e
--- /dev/null
+++ b/libgo/go/cmd/vet/testdata/src/deadcode/deadcode.go
@@ -0,0 +1,14 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains tests for the dead code checker.
+
+package deadcode
+
+func _() int {
+ print(1)
+ return 2
+ println() // ERROR "unreachable code"
+ return 3
+}
diff --git a/libgo/go/cmd/vet/testdata/src/httpresponse/httpresponse.go b/libgo/go/cmd/vet/testdata/src/httpresponse/httpresponse.go
new file mode 100644
index 00000000000..6141f6e06dc
--- /dev/null
+++ b/libgo/go/cmd/vet/testdata/src/httpresponse/httpresponse.go
@@ -0,0 +1,22 @@
+package httpresponse
+
+import (
+ "log"
+ "net/http"
+)
+
+func goodHTTPGet() {
+ res, err := http.Get("http://foo.com")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer res.Body.Close()
+}
+
+func badHTTPGet() {
+ res, err := http.Get("http://foo.com")
+ defer res.Body.Close() // ERROR "using res before checking for errors"
+ if err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/libgo/go/cmd/vet/testdata/src/lostcancel/lostcancel.go b/libgo/go/cmd/vet/testdata/src/lostcancel/lostcancel.go
new file mode 100644
index 00000000000..1bbb22d27b4
--- /dev/null
+++ b/libgo/go/cmd/vet/testdata/src/lostcancel/lostcancel.go
@@ -0,0 +1,14 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package lostcancel
+
+import "context"
+
+func _() {
+ var _, cancel = context.WithCancel(context.Background()) // ERROR "the cancel function is not used on all paths \(possible context leak\)"
+ if false {
+ _ = cancel
+ }
+} // ERROR "this return statement may be reached without using the cancel var defined on line 10"
diff --git a/libgo/go/cmd/vet/testdata/method.go b/libgo/go/cmd/vet/testdata/src/method/method.go
index 52b500df272..51c3f65fcc7 100644
--- a/libgo/go/cmd/vet/testdata/method.go
+++ b/libgo/go/cmd/vet/testdata/src/method/method.go
@@ -2,21 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// This file contains tests for the canonical method checker.
-
// This file contains the code to check canonical methods.
-package testdata
+package method
-import (
- "fmt"
-)
+import "fmt"
type MethodTest int
-func (t *MethodTest) Scan(x fmt.ScanState, c byte) { // ERROR "should have signature Scan"
-}
-
-type MethodTestInterface interface {
- ReadByte() byte // ERROR "should have signature ReadByte"
+func (t *MethodTest) Scan(x fmt.ScanState, c byte) { // ERROR "should have signature Scan\(fmt\.ScanState, rune\) error"
}
diff --git a/libgo/go/cmd/vet/testdata/src/nilfunc/nilfunc.go b/libgo/go/cmd/vet/testdata/src/nilfunc/nilfunc.go
new file mode 100644
index 00000000000..c34d60e0521
--- /dev/null
+++ b/libgo/go/cmd/vet/testdata/src/nilfunc/nilfunc.go
@@ -0,0 +1,13 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package nilfunc
+
+func F() {}
+
+func Comparison() {
+ if F == nil { // ERROR "comparison of function F == nil is always false"
+ panic("can't happen")
+ }
+}
diff --git a/libgo/go/cmd/vet/testdata/print.go b/libgo/go/cmd/vet/testdata/src/print/print.go
index ecafed5fa2f..6bacd0fd747 100644
--- a/libgo/go/cmd/vet/testdata/print.go
+++ b/libgo/go/cmd/vet/testdata/src/print/print.go
@@ -4,16 +4,10 @@
// This file contains tests for the printf checker.
-// TODO(rsc): The user-defined wrapper tests are commented out
-// because they produced too many false positives when vet was
-// enabled during go test. See the TODO in ../print.go for a plan
-// to fix that; when it's fixed, uncomment the user-defined wrapper tests.
-
-package testdata
+package print
import (
"fmt"
- . "fmt"
logpkg "log" // renamed to make it harder to see
"math"
"os"
@@ -103,7 +97,7 @@ func PrintfTests() {
fmt.Printf("%s", stringerarrayv)
fmt.Printf("%v", notstringerarrayv)
fmt.Printf("%T", notstringerarrayv)
- fmt.Printf("%d", new(Formatter))
+ fmt.Printf("%d", new(fmt.Formatter))
fmt.Printf("%*%", 2) // Ridiculous but allowed.
fmt.Printf("%s", interface{}(nil)) // Nothing useful we can say.
@@ -132,16 +126,16 @@ func PrintfTests() {
fmt.Printf("%U", x) // ERROR "Printf format %U has arg x of wrong type float64"
fmt.Printf("%x", nil) // ERROR "Printf format %x has arg nil of wrong type untyped nil"
fmt.Printf("%X", 2.3) // ERROR "Printf format %X has arg 2.3 of wrong type float64"
- fmt.Printf("%s", stringerv) // ERROR "Printf format %s has arg stringerv of wrong type testdata.ptrStringer"
- fmt.Printf("%t", stringerv) // ERROR "Printf format %t has arg stringerv of wrong type testdata.ptrStringer"
- fmt.Printf("%s", embeddedStringerv) // ERROR "Printf format %s has arg embeddedStringerv of wrong type testdata.embeddedStringer"
- fmt.Printf("%t", embeddedStringerv) // ERROR "Printf format %t has arg embeddedStringerv of wrong type testdata.embeddedStringer"
- fmt.Printf("%q", notstringerv) // ERROR "Printf format %q has arg notstringerv of wrong type testdata.notstringer"
- fmt.Printf("%t", notstringerv) // ERROR "Printf format %t has arg notstringerv of wrong type testdata.notstringer"
- fmt.Printf("%t", stringerarrayv) // ERROR "Printf format %t has arg stringerarrayv of wrong type testdata.stringerarray"
- fmt.Printf("%t", notstringerarrayv) // ERROR "Printf format %t has arg notstringerarrayv of wrong type testdata.notstringerarray"
- fmt.Printf("%q", notstringerarrayv) // ERROR "Printf format %q has arg notstringerarrayv of wrong type testdata.notstringerarray"
- fmt.Printf("%d", BoolFormatter(true)) // ERROR "Printf format %d has arg BoolFormatter\(true\) of wrong type testdata.BoolFormatter"
+ fmt.Printf("%s", stringerv) // ERROR "Printf format %s has arg stringerv of wrong type print.ptrStringer"
+ fmt.Printf("%t", stringerv) // ERROR "Printf format %t has arg stringerv of wrong type print.ptrStringer"
+ fmt.Printf("%s", embeddedStringerv) // ERROR "Printf format %s has arg embeddedStringerv of wrong type print.embeddedStringer"
+ fmt.Printf("%t", embeddedStringerv) // ERROR "Printf format %t has arg embeddedStringerv of wrong type print.embeddedStringer"
+ fmt.Printf("%q", notstringerv) // ERROR "Printf format %q has arg notstringerv of wrong type print.notstringer"
+ fmt.Printf("%t", notstringerv) // ERROR "Printf format %t has arg notstringerv of wrong type print.notstringer"
+ fmt.Printf("%t", stringerarrayv) // ERROR "Printf format %t has arg stringerarrayv of wrong type print.stringerarray"
+ fmt.Printf("%t", notstringerarrayv) // ERROR "Printf format %t has arg notstringerarrayv of wrong type print.notstringerarray"
+ fmt.Printf("%q", notstringerarrayv) // ERROR "Printf format %q has arg notstringerarrayv of wrong type print.notstringerarray"
+ fmt.Printf("%d", BoolFormatter(true)) // ERROR "Printf format %d has arg BoolFormatter\(true\) of wrong type print.BoolFormatter"
fmt.Printf("%z", FormatterVal(true)) // correct (the type is responsible for formatting)
fmt.Printf("%d", FormatterVal(true)) // correct (the type is responsible for formatting)
fmt.Printf("%s", nonemptyinterface) // correct (the type is responsible for formatting)
@@ -192,10 +186,10 @@ func PrintfTests() {
Printf("d%", 2) // ERROR "Printf format % is missing verb at end of string"
Printf("%d", percentDV)
Printf("%d", &percentDV)
- Printf("%d", notPercentDV) // ERROR "Printf format %d has arg notPercentDV of wrong type testdata.notPercentDStruct"
- Printf("%d", &notPercentDV) // ERROR "Printf format %d has arg &notPercentDV of wrong type \*testdata.notPercentDStruct"
+ Printf("%d", notPercentDV) // ERROR "Printf format %d has arg notPercentDV of wrong type print.notPercentDStruct"
+ Printf("%d", &notPercentDV) // ERROR "Printf format %d has arg &notPercentDV of wrong type \*print.notPercentDStruct"
Printf("%p", &notPercentDV) // Works regardless: we print it as a pointer.
- Printf("%q", &percentDV) // ERROR "Printf format %q has arg &percentDV of wrong type \*testdata.percentDStruct"
+ Printf("%q", &percentDV) // ERROR "Printf format %q has arg &percentDV of wrong type \*print.percentDStruct"
Printf("%s", percentSV)
Printf("%s", &percentSV)
// Good argument reorderings.
@@ -240,7 +234,7 @@ func PrintfTests() {
Printf("%T", someFunction) // ok: maybe someone wants to see the type
// Bug: used to recur forever.
Printf("%p %x", recursiveStructV, recursiveStructV.next)
- Printf("%p %x", recursiveStruct1V, recursiveStruct1V.next)
+ Printf("%p %x", recursiveStruct1V, recursiveStruct1V.next) // ERROR "Printf format %x has arg recursiveStruct1V\.next of wrong type \*print\.RecursiveStruct2"
Printf("%p %x", recursiveSliceV, recursiveSliceV)
Printf("%p %x", recursiveMapV, recursiveMapV)
// Special handling for Log.
@@ -250,13 +244,13 @@ func PrintfTests() {
t.Logf("%d", 3)
t.Logf("%d", "hi") // ERROR "Logf format %d has arg \x22hi\x22 of wrong type string"
- // Errorf(1, "%d", 3) // OK
- // Errorf(1, "%d", "hi") // no error "Errorf format %d has arg \x22hi\x22 of wrong type string"
+ Errorf(1, "%d", 3) // OK
+ Errorf(1, "%d", "hi") // ERROR "Errorf format %d has arg \x22hi\x22 of wrong type string"
// Multiple string arguments before variadic args
- // errorf("WARNING", "foobar") // OK
- // errorf("INFO", "s=%s, n=%d", "foo", 1) // OK
- // errorf("ERROR", "%d") // no error "errorf format %d reads arg #1, but call has 0 args"
+ errorf("WARNING", "foobar") // OK
+ errorf("INFO", "s=%s, n=%d", "foo", 1) // OK
+ errorf("ERROR", "%d") // ERROR "errorf format %d reads arg #1, but call has 0 args"
// Printf from external package
// externalprintf.Printf("%d", 42) // OK
@@ -348,46 +342,32 @@ func (ss *someStruct) log(f func(), args ...interface{}) {}
// A function we use as a function value; it has no other purpose.
func someFunction() {}
-/*
// Printf is used by the test so we must declare it.
func Printf(format string, args ...interface{}) {
- panic("don't call - testing only")
+ fmt.Printf(format, args...)
}
// Println is used by the test so we must declare it.
func Println(args ...interface{}) {
- panic("don't call - testing only")
-}
-
-// Logf is used by the test so we must declare it.
-func Logf(format string, args ...interface{}) {
- panic("don't call - testing only")
+ fmt.Println(args...)
}
-// Log is used by the test so we must declare it.
-func Log(args ...interface{}) {
- panic("don't call - testing only")
-}
-*/
-
// printf is used by the test so we must declare it.
func printf(format string, args ...interface{}) {
- panic("don't call - testing only")
+ fmt.Printf(format, args...)
}
-/*
// Errorf is used by the test for a case in which the first parameter
// is not a format string.
func Errorf(i int, format string, args ...interface{}) {
- panic("don't call - testing only")
+ _ = fmt.Errorf(format, args...)
}
// errorf is used by the test for a case in which the function accepts multiple
// string parameters before variadic arguments
func errorf(level, format string, args ...interface{}) {
- panic("don't call - testing only")
+ _ = fmt.Errorf(format, args...)
}
-*/
// multi is used by the test.
func multi() []interface{} {
@@ -607,37 +587,37 @@ func UnexportedStringerOrError() {
fmt.Printf("%s", unexportedInterface{3}) // ok; we can't see the problem
us := unexportedStringer{}
- fmt.Printf("%s", us) // ERROR "Printf format %s has arg us of wrong type testdata.unexportedStringer"
- fmt.Printf("%s", &us) // ERROR "Printf format %s has arg &us of wrong type [*]testdata.unexportedStringer"
+ fmt.Printf("%s", us) // ERROR "Printf format %s has arg us of wrong type print.unexportedStringer"
+ fmt.Printf("%s", &us) // ERROR "Printf format %s has arg &us of wrong type [*]print.unexportedStringer"
usf := unexportedStringerOtherFields{
s: "foo",
S: "bar",
}
- fmt.Printf("%s", usf) // ERROR "Printf format %s has arg usf of wrong type testdata.unexportedStringerOtherFields"
- fmt.Printf("%s", &usf) // ERROR "Printf format %s has arg &usf of wrong type [*]testdata.unexportedStringerOtherFields"
+ fmt.Printf("%s", usf) // ERROR "Printf format %s has arg usf of wrong type print.unexportedStringerOtherFields"
+ fmt.Printf("%s", &usf) // ERROR "Printf format %s has arg &usf of wrong type [*]print.unexportedStringerOtherFields"
ue := unexportedError{
e: &errorer{},
}
- fmt.Printf("%s", ue) // ERROR "Printf format %s has arg ue of wrong type testdata.unexportedError"
- fmt.Printf("%s", &ue) // ERROR "Printf format %s has arg &ue of wrong type [*]testdata.unexportedError"
+ fmt.Printf("%s", ue) // ERROR "Printf format %s has arg ue of wrong type print.unexportedError"
+ fmt.Printf("%s", &ue) // ERROR "Printf format %s has arg &ue of wrong type [*]print.unexportedError"
uef := unexportedErrorOtherFields{
s: "foo",
e: &errorer{},
S: "bar",
}
- fmt.Printf("%s", uef) // ERROR "Printf format %s has arg uef of wrong type testdata.unexportedErrorOtherFields"
- fmt.Printf("%s", &uef) // ERROR "Printf format %s has arg &uef of wrong type [*]testdata.unexportedErrorOtherFields"
+ fmt.Printf("%s", uef) // ERROR "Printf format %s has arg uef of wrong type print.unexportedErrorOtherFields"
+ fmt.Printf("%s", &uef) // ERROR "Printf format %s has arg &uef of wrong type [*]print.unexportedErrorOtherFields"
uce := unexportedCustomError{
e: errorer{},
}
- fmt.Printf("%s", uce) // ERROR "Printf format %s has arg uce of wrong type testdata.unexportedCustomError"
+ fmt.Printf("%s", uce) // ERROR "Printf format %s has arg uce of wrong type print.unexportedCustomError"
uei := unexportedErrorInterface{}
- fmt.Printf("%s", uei) // ERROR "Printf format %s has arg uei of wrong type testdata.unexportedErrorInterface"
+ fmt.Printf("%s", uei) // ERROR "Printf format %s has arg uei of wrong type print.unexportedErrorInterface"
fmt.Println("foo\n", "bar") // not an error
fmt.Println("foo\n") // ERROR "Println arg list ends with redundant newline"
@@ -647,7 +627,7 @@ func UnexportedStringerOrError() {
intSlice := []int{3, 4}
fmt.Printf("%s", intSlice) // ERROR "Printf format %s has arg intSlice of wrong type \[\]int"
nonStringerArray := [1]unexportedStringer{{}}
- fmt.Printf("%s", nonStringerArray) // ERROR "Printf format %s has arg nonStringerArray of wrong type \[1\]testdata.unexportedStringer"
+ fmt.Printf("%s", nonStringerArray) // ERROR "Printf format %s has arg nonStringerArray of wrong type \[1\]print.unexportedStringer"
fmt.Printf("%s", []stringer{3, 4}) // not an error
fmt.Printf("%s", [2]stringer{3, 4}) // not an error
}
@@ -665,3 +645,37 @@ func dbg(format string, args ...interface{}) {
}
fmt.Printf(format, args...)
}
+
+func PointersToCompoundTypes() {
+ stringSlice := []string{"a", "b"}
+ fmt.Printf("%s", &stringSlice) // not an error
+
+ intSlice := []int{3, 4}
+ fmt.Printf("%s", &intSlice) // ERROR "Printf format %s has arg &intSlice of wrong type \*\[\]int"
+
+ stringArray := [2]string{"a", "b"}
+ fmt.Printf("%s", &stringArray) // not an error
+
+ intArray := [2]int{3, 4}
+ fmt.Printf("%s", &intArray) // ERROR "Printf format %s has arg &intArray of wrong type \*\[2\]int"
+
+ stringStruct := struct{ F string }{"foo"}
+ fmt.Printf("%s", &stringStruct) // not an error
+
+ intStruct := struct{ F int }{3}
+ fmt.Printf("%s", &intStruct) // ERROR "Printf format %s has arg &intStruct of wrong type \*struct{F int}"
+
+ stringMap := map[string]string{"foo": "bar"}
+ fmt.Printf("%s", &stringMap) // not an error
+
+ intMap := map[int]int{3: 4}
+ fmt.Printf("%s", &intMap) // ERROR "Printf format %s has arg &intMap of wrong type \*map\[int\]int"
+
+ type T2 struct {
+ X string
+ }
+ type T1 struct {
+ X *T2
+ }
+ fmt.Printf("%s\n", T1{&T2{"x"}}) // ERROR "Printf format %s has arg T1{&T2{.x.}} of wrong type print\.T1"
+}
diff --git a/libgo/go/cmd/vet/testdata/src/rangeloop/rangeloop.go b/libgo/go/cmd/vet/testdata/src/rangeloop/rangeloop.go
new file mode 100644
index 00000000000..4e215641869
--- /dev/null
+++ b/libgo/go/cmd/vet/testdata/src/rangeloop/rangeloop.go
@@ -0,0 +1,17 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains tests for the rangeloop checker.
+
+package rangeloop
+
+func RangeLoopTests() {
+ var s []int
+ for i, v := range s {
+ go func() {
+ println(i) // ERROR "loop variable i captured by func literal"
+ println(v) // ERROR "loop variable v captured by func literal"
+ }()
+ }
+}
diff --git a/libgo/go/cmd/vet/testdata/src/shift/shift.go b/libgo/go/cmd/vet/testdata/src/shift/shift.go
new file mode 100644
index 00000000000..6b7a5ac9e18
--- /dev/null
+++ b/libgo/go/cmd/vet/testdata/src/shift/shift.go
@@ -0,0 +1,13 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains tests for the suspicious shift checker.
+
+package shift
+
+func ShiftTest() {
+ var i8 int8
+ _ = i8 << 7
+ _ = (i8 + 1) << 8 // ERROR ".i8 . 1. .8 bits. too small for shift of 8"
+}
diff --git a/libgo/go/cmd/vet/testdata/src/structtag/structtag.go b/libgo/go/cmd/vet/testdata/src/structtag/structtag.go
new file mode 100644
index 00000000000..cbcc4533760
--- /dev/null
+++ b/libgo/go/cmd/vet/testdata/src/structtag/structtag.go
@@ -0,0 +1,11 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains the test for canonical struct tags.
+
+package structtag
+
+type StructTagTest struct {
+ A int "hello" // ERROR "`hello` not compatible with reflect.StructTag.Get: bad syntax for struct tag pair"
+}
diff --git a/libgo/go/cmd/vet/testdata/tagtest/file1.go b/libgo/go/cmd/vet/testdata/src/tagtest/file1.go
index 22a1509acc0..47fe3c80afe 100644
--- a/libgo/go/cmd/vet/testdata/tagtest/file1.go
+++ b/libgo/go/cmd/vet/testdata/src/tagtest/file1.go
@@ -6,5 +6,8 @@
package main
+import "fmt"
+
func main() {
+ fmt.Printf("%s", 0)
}
diff --git a/libgo/go/cmd/vet/testdata/tagtest/file2.go b/libgo/go/cmd/vet/testdata/src/tagtest/file2.go
index ba7dd91bbd8..1f45efcbf2f 100644
--- a/libgo/go/cmd/vet/testdata/tagtest/file2.go
+++ b/libgo/go/cmd/vet/testdata/src/tagtest/file2.go
@@ -6,5 +6,8 @@
package main
-func ignore() {
+import "fmt"
+
+func main() {
+ fmt.Printf("%s", 0)
}
diff --git a/libgo/go/cmd/vet/testdata/testingpkg/tests.go b/libgo/go/cmd/vet/testdata/src/testingpkg/tests.go
index 69d29d3c6c6..69d29d3c6c6 100644
--- a/libgo/go/cmd/vet/testdata/testingpkg/tests.go
+++ b/libgo/go/cmd/vet/testdata/src/testingpkg/tests.go
diff --git a/libgo/go/cmd/vet/testdata/src/testingpkg/tests_test.go b/libgo/go/cmd/vet/testdata/src/testingpkg/tests_test.go
new file mode 100644
index 00000000000..09bb98d980e
--- /dev/null
+++ b/libgo/go/cmd/vet/testdata/src/testingpkg/tests_test.go
@@ -0,0 +1,3 @@
+package testdata
+
+func Example_BadSuffix() {} // ERROR "Example_BadSuffix has malformed example suffix: BadSuffix"
diff --git a/libgo/go/cmd/vet/testdata/src/unmarshal/unmarshal.go b/libgo/go/cmd/vet/testdata/src/unmarshal/unmarshal.go
new file mode 100644
index 00000000000..b387bbbd234
--- /dev/null
+++ b/libgo/go/cmd/vet/testdata/src/unmarshal/unmarshal.go
@@ -0,0 +1,18 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains tests for the unmarshal checker.
+
+package unmarshal
+
+import "encoding/json"
+
+func _() {
+ type t struct {
+ a int
+ }
+ var v t
+
+ json.Unmarshal([]byte{}, v) // ERROR "call of Unmarshal passes non-pointer as second argument"
+}
diff --git a/libgo/go/cmd/vet/testdata/src/unsafeptr/unsafeptr.go b/libgo/go/cmd/vet/testdata/src/unsafeptr/unsafeptr.go
new file mode 100644
index 00000000000..e9b866ea21b
--- /dev/null
+++ b/libgo/go/cmd/vet/testdata/src/unsafeptr/unsafeptr.go
@@ -0,0 +1,14 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package unsafeptr
+
+import "unsafe"
+
+func _() {
+ var x unsafe.Pointer
+ var y uintptr
+ x = unsafe.Pointer(y) // ERROR "possible misuse of unsafe.Pointer"
+ _ = x
+}
diff --git a/libgo/go/cmd/vet/testdata/src/unused/unused.go b/libgo/go/cmd/vet/testdata/src/unused/unused.go
new file mode 100644
index 00000000000..1e83e90d68f
--- /dev/null
+++ b/libgo/go/cmd/vet/testdata/src/unused/unused.go
@@ -0,0 +1,13 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains tests for the unusedresult checker.
+
+package unused
+
+import "fmt"
+
+func _() {
+ fmt.Errorf("") // ERROR "result of fmt.Errorf call not used"
+}
diff --git a/libgo/go/cmd/vet/testdata/structtag.go b/libgo/go/cmd/vet/testdata/structtag.go
deleted file mode 100644
index ce21e803c80..00000000000
--- a/libgo/go/cmd/vet/testdata/structtag.go
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file contains the test for canonical struct tags.
-
-package testdata
-
-import "encoding/xml"
-
-type StructTagTest struct {
- A int "hello" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag pair"
- B int "\tx:\"y\"" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag key"
- C int "x:\"y\"\tx:\"y\"" // ERROR "not compatible with reflect.StructTag.Get"
- D int "x:`y`" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value"
- E int "ct\brl:\"char\"" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag pair"
- F int `:"emptykey"` // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag key"
- G int `x:"noEndQuote` // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value"
- H int `x:"trunc\x0"` // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value"
- I int `x:"foo",y:"bar"` // ERROR "not compatible with reflect.StructTag.Get: key:.value. pairs not separated by spaces"
- J int `x:"foo"y:"bar"` // ERROR "not compatible with reflect.StructTag.Get: key:.value. pairs not separated by spaces"
- OK0 int `x:"y" u:"v" w:""`
- OK1 int `x:"y:z" u:"v" w:""` // note multiple colons.
- OK2 int "k0:\"values contain spaces\" k1:\"literal\ttabs\" k2:\"and\\tescaped\\tabs\""
- OK3 int `under_scores:"and" CAPS:"ARE_OK"`
-}
-
-type UnexportedEncodingTagTest struct {
- x int `json:"xx"` // ERROR "struct field x has json tag but is not exported"
- y int `xml:"yy"` // ERROR "struct field y has xml tag but is not exported"
- z int
- A int `json:"aa" xml:"bb"`
-}
-
-type unexp struct{}
-
-type JSONEmbeddedField struct {
- UnexportedEncodingTagTest `is:"embedded"`
- unexp `is:"embedded,notexported" json:"unexp"` // OK for now, see issue 7363
-}
-
-type AnonymousJSON struct{}
-type AnonymousXML struct{}
-
-type DuplicateJSONFields struct {
- JSON int `json:"a"`
- DuplicateJSON int `json:"a"` // ERROR "struct field DuplicateJSON repeats json tag .a. also at structtag.go:46"
- IgnoredJSON int `json:"-"`
- OtherIgnoredJSON int `json:"-"`
- OmitJSON int `json:",omitempty"`
- OtherOmitJSON int `json:",omitempty"`
- DuplicateOmitJSON int `json:"a,omitempty"` // ERROR "struct field DuplicateOmitJSON repeats json tag .a. also at structtag.go:46"
- NonJSON int `foo:"a"`
- DuplicateNonJSON int `foo:"a"`
- Embedded struct {
- DuplicateJSON int `json:"a"` // OK because its not in the same struct type
- }
- AnonymousJSON `json:"a"` // ERROR "struct field AnonymousJSON repeats json tag .a. also at structtag.go:46"
-
- XML int `xml:"a"`
- DuplicateXML int `xml:"a"` // ERROR "struct field DuplicateXML repeats xml tag .a. also at structtag.go:60"
- IgnoredXML int `xml:"-"`
- OtherIgnoredXML int `xml:"-"`
- OmitXML int `xml:",omitempty"`
- OtherOmitXML int `xml:",omitempty"`
- DuplicateOmitXML int `xml:"a,omitempty"` // ERROR "struct field DuplicateOmitXML repeats xml tag .a. also at structtag.go:60"
- NonXML int `foo:"a"`
- DuplicateNonXML int `foo:"a"`
- Embedded struct {
- DuplicateXML int `xml:"a"` // OK because its not in the same struct type
- }
- AnonymousXML `xml:"a"` // ERROR "struct field AnonymousXML repeats xml tag .a. also at structtag.go:60"
- Attribute struct {
- XMLName xml.Name `xml:"b"`
- NoDup int `xml:"b"` // OK because XMLName above affects enclosing struct.
- Attr int `xml:"b,attr"` // OK because <b b="0"><b>0</b></b> is valid.
- DupAttr int `xml:"b,attr"` // ERROR "struct field DupAttr repeats xml attribute tag .b. also at structtag.go:76"
- DupOmitAttr int `xml:"b,omitempty,attr"` // ERROR "struct field DupOmitAttr repeats xml attribute tag .b. also at structtag.go:76"
-
- AnonymousXML `xml:"b,attr"` // ERROR "struct field AnonymousXML repeats xml attribute tag .b. also at structtag.go:76"
- }
-}
-
-type UnexpectedSpacetest struct {
- A int `json:"a,omitempty"`
- B int `json:"b, omitempty"` // ERROR "suspicious space in struct tag value"
- C int `json:"c ,omitempty"`
- D int `json:"d,omitempty, string"` // ERROR "suspicious space in struct tag value"
- E int `xml:"e local"`
- F int `xml:"f "` // ERROR "suspicious space in struct tag value"
- G int `xml:" g"` // ERROR "suspicious space in struct tag value"
- H int `xml:"h ,omitempty"` // ERROR "suspicious space in struct tag value"
- I int `xml:"i, omitempty"` // ERROR "suspicious space in struct tag value"
- J int `xml:"j local ,omitempty"` // ERROR "suspicious space in struct tag value"
- K int `xml:"k local, omitempty"` // ERROR "suspicious space in struct tag value"
- L int `xml:" l local,omitempty"` // ERROR "suspicious space in struct tag value"
- M int `xml:"m local,omitempty"` // ERROR "suspicious space in struct tag value"
- N int `xml:" "` // ERROR "suspicious space in struct tag value"
- O int `xml:""`
- P int `xml:","`
- Q int `foo:" doesn't care "`
-}
diff --git a/libgo/go/cmd/vet/testdata/testingpkg/tests_test.go b/libgo/go/cmd/vet/testdata/testingpkg/tests_test.go
deleted file mode 100644
index f5bbc3922a9..00000000000
--- a/libgo/go/cmd/vet/testdata/testingpkg/tests_test.go
+++ /dev/null
@@ -1,74 +0,0 @@
-package testdata
-
-import (
- "testing"
-)
-
-// Buf is a ...
-type Buf []byte
-
-// Append ...
-func (*Buf) Append([]byte) {}
-
-func (Buf) Reset() {}
-
-func (Buf) Len() int { return 0 }
-
-// DefaultBuf is a ...
-var DefaultBuf Buf
-
-func Example() {} // OK because is package-level.
-
-func Example_goodSuffix() // OK because refers to suffix annotation.
-
-func Example_BadSuffix() // ERROR "Example_BadSuffix has malformed example suffix: BadSuffix"
-
-func ExampleBuf() // OK because refers to known top-level type.
-
-func ExampleBuf_Append() {} // OK because refers to known method.
-
-func ExampleBuf_Clear() {} // ERROR "ExampleBuf_Clear refers to unknown field or method: Buf.Clear"
-
-func ExampleBuf_suffix() {} // OK because refers to suffix annotation.
-
-func ExampleBuf_Append_Bad() {} // ERROR "ExampleBuf_Append_Bad has malformed example suffix: Bad"
-
-func ExampleBuf_Append_suffix() {} // OK because refers to known method with valid suffix.
-
-func ExampleDefaultBuf() {} // OK because refers to top-level identifier.
-
-func ExampleBuf_Reset() bool { return true } // ERROR "ExampleBuf_Reset should return nothing"
-
-func ExampleBuf_Len(i int) {} // ERROR "ExampleBuf_Len should be niladic"
-
-// "Puffer" is German for "Buffer".
-
-func ExamplePuffer() // ERROR "ExamplePuffer refers to unknown identifier: Puffer"
-
-func ExamplePuffer_Append() // ERROR "ExamplePuffer_Append refers to unknown identifier: Puffer"
-
-func ExamplePuffer_suffix() // ERROR "ExamplePuffer_suffix refers to unknown identifier: Puffer"
-
-func nonTest() {} // OK because it doesn't start with "Test".
-
-func (Buf) TesthasReceiver() {} // OK because it has a receiver.
-
-func TestOKSuffix(*testing.T) {} // OK because first char after "Test" is Uppercase.
-
-func TestÜnicodeWorks(*testing.T) {} // OK because the first char after "Test" is Uppercase.
-
-func TestbadSuffix(*testing.T) {} // ERROR "first letter after 'Test' must not be lowercase"
-
-func TestemptyImportBadSuffix(*T) {} // ERROR "first letter after 'Test' must not be lowercase"
-
-func Test(*testing.T) {} // OK "Test" on its own is considered a test.
-
-func Testify() {} // OK because it takes no parameters.
-
-func TesttooManyParams(*testing.T, string) {} // OK because it takes too many parameters.
-
-func TesttooManyNames(a, b *testing.T) {} // OK because it takes too many names.
-
-func TestnoTParam(string) {} // OK because it doesn't take a *testing.T
-
-func BenchmarkbadSuffix(*testing.B) {} // ERROR "first letter after 'Benchmark' must not be lowercase"
diff --git a/libgo/go/cmd/vet/testdata/unsafeptr.go b/libgo/go/cmd/vet/testdata/unsafeptr.go
deleted file mode 100644
index ce852009ea7..00000000000
--- a/libgo/go/cmd/vet/testdata/unsafeptr.go
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package testdata
-
-import (
- "reflect"
- "unsafe"
-)
-
-func f() {
- var x unsafe.Pointer
- var y uintptr
- x = unsafe.Pointer(y) // ERROR "possible misuse of unsafe.Pointer"
- y = uintptr(x)
-
- // only allowed pointer arithmetic is ptr +/-/&^ num.
- // num+ptr is technically okay but still flagged: write ptr+num instead.
- x = unsafe.Pointer(uintptr(x) + 1)
- x = unsafe.Pointer(1 + uintptr(x)) // ERROR "possible misuse of unsafe.Pointer"
- x = unsafe.Pointer(uintptr(x) + uintptr(x)) // ERROR "possible misuse of unsafe.Pointer"
- x = unsafe.Pointer(uintptr(x) - 1)
- x = unsafe.Pointer(1 - uintptr(x)) // ERROR "possible misuse of unsafe.Pointer"
- x = unsafe.Pointer(uintptr(x) &^ 3)
- x = unsafe.Pointer(1 &^ uintptr(x)) // ERROR "possible misuse of unsafe.Pointer"
-
- // certain uses of reflect are okay
- var v reflect.Value
- x = unsafe.Pointer(v.Pointer())
- x = unsafe.Pointer(v.UnsafeAddr())
- var s1 *reflect.StringHeader
- x = unsafe.Pointer(s1.Data)
- var s2 *reflect.SliceHeader
- x = unsafe.Pointer(s2.Data)
- var s3 reflect.StringHeader
- x = unsafe.Pointer(s3.Data) // ERROR "possible misuse of unsafe.Pointer"
- var s4 reflect.SliceHeader
- x = unsafe.Pointer(s4.Data) // ERROR "possible misuse of unsafe.Pointer"
-
- // but only in reflect
- var vv V
- x = unsafe.Pointer(vv.Pointer()) // ERROR "possible misuse of unsafe.Pointer"
- x = unsafe.Pointer(vv.UnsafeAddr()) // ERROR "possible misuse of unsafe.Pointer"
- var ss1 *StringHeader
- x = unsafe.Pointer(ss1.Data) // ERROR "possible misuse of unsafe.Pointer"
- var ss2 *SliceHeader
- x = unsafe.Pointer(ss2.Data) // ERROR "possible misuse of unsafe.Pointer"
-
-}
-
-type V interface {
- Pointer() uintptr
- UnsafeAddr() uintptr
-}
-
-type StringHeader struct {
- Data uintptr
-}
-
-type SliceHeader struct {
- Data uintptr
-}
diff --git a/libgo/go/cmd/vet/testdata/unused.go b/libgo/go/cmd/vet/testdata/unused.go
deleted file mode 100644
index d50f6594d9b..00000000000
--- a/libgo/go/cmd/vet/testdata/unused.go
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file contains tests for the unusedresult checker.
-
-package testdata
-
-import (
- "bytes"
- "errors"
- "fmt"
-)
-
-func _() {
- fmt.Errorf("") // ERROR "result of fmt.Errorf call not used"
- _ = fmt.Errorf("")
-
- errors.New("") // ERROR "result of errors.New call not used"
-
- err := errors.New("")
- err.Error() // ERROR "result of \(error\).Error call not used"
-
- var buf bytes.Buffer
- buf.String() // ERROR "result of \(bytes.Buffer\).String call not used"
-
- fmt.Sprint("") // ERROR "result of fmt.Sprint call not used"
- fmt.Sprintf("") // ERROR "result of fmt.Sprintf call not used"
-}
diff --git a/libgo/go/cmd/vet/tests.go b/libgo/go/cmd/vet/tests.go
deleted file mode 100644
index 5b157084fa2..00000000000
--- a/libgo/go/cmd/vet/tests.go
+++ /dev/null
@@ -1,187 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "go/ast"
- "go/types"
- "strings"
- "unicode"
- "unicode/utf8"
-)
-
-func init() {
- register("tests",
- "check for common mistaken usages of tests/documentation examples",
- checkTestFunctions,
- funcDecl)
-}
-
-func isExampleSuffix(s string) bool {
- r, size := utf8.DecodeRuneInString(s)
- return size > 0 && unicode.IsLower(r)
-}
-
-func isTestSuffix(name string) bool {
- if len(name) == 0 {
- // "Test" is ok.
- return true
- }
- r, _ := utf8.DecodeRuneInString(name)
- return !unicode.IsLower(r)
-}
-
-func isTestParam(typ ast.Expr, wantType string) bool {
- ptr, ok := typ.(*ast.StarExpr)
- if !ok {
- // Not a pointer.
- return false
- }
- // No easy way of making sure it's a *testing.T or *testing.B:
- // ensure the name of the type matches.
- if name, ok := ptr.X.(*ast.Ident); ok {
- return name.Name == wantType
- }
- if sel, ok := ptr.X.(*ast.SelectorExpr); ok {
- return sel.Sel.Name == wantType
- }
- return false
-}
-
-func lookup(name string, scopes []*types.Scope) types.Object {
- for _, scope := range scopes {
- if o := scope.Lookup(name); o != nil {
- return o
- }
- }
- return nil
-}
-
-func extendedScope(f *File) []*types.Scope {
- scopes := []*types.Scope{f.pkg.typesPkg.Scope()}
- if f.basePkg != nil {
- scopes = append(scopes, f.basePkg.typesPkg.Scope())
- } else {
- // If basePkg is not specified (e.g. when checking a single file) try to
- // find it among imports.
- pkgName := f.pkg.typesPkg.Name()
- if strings.HasSuffix(pkgName, "_test") {
- basePkgName := strings.TrimSuffix(pkgName, "_test")
- for _, p := range f.pkg.typesPkg.Imports() {
- if p.Name() == basePkgName {
- scopes = append(scopes, p.Scope())
- break
- }
- }
- }
- }
- return scopes
-}
-
-func checkExample(fn *ast.FuncDecl, f *File, report reporter) {
- fnName := fn.Name.Name
- if params := fn.Type.Params; len(params.List) != 0 {
- report("%s should be niladic", fnName)
- }
- if results := fn.Type.Results; results != nil && len(results.List) != 0 {
- report("%s should return nothing", fnName)
- }
-
- if filesRun && !includesNonTest {
- // The coherence checks between a test and the package it tests
- // will report false positives if no non-test files have
- // been provided.
- return
- }
-
- if fnName == "Example" {
- // Nothing more to do.
- return
- }
-
- var (
- exName = strings.TrimPrefix(fnName, "Example")
- elems = strings.SplitN(exName, "_", 3)
- ident = elems[0]
- obj = lookup(ident, extendedScope(f))
- )
- if ident != "" && obj == nil {
- // Check ExampleFoo and ExampleBadFoo.
- report("%s refers to unknown identifier: %s", fnName, ident)
- // Abort since obj is absent and no subsequent checks can be performed.
- return
- }
- if len(elems) < 2 {
- // Nothing more to do.
- return
- }
-
- if ident == "" {
- // Check Example_suffix and Example_BadSuffix.
- if residual := strings.TrimPrefix(exName, "_"); !isExampleSuffix(residual) {
- report("%s has malformed example suffix: %s", fnName, residual)
- }
- return
- }
-
- mmbr := elems[1]
- if !isExampleSuffix(mmbr) {
- // Check ExampleFoo_Method and ExampleFoo_BadMethod.
- if obj, _, _ := types.LookupFieldOrMethod(obj.Type(), true, obj.Pkg(), mmbr); obj == nil {
- report("%s refers to unknown field or method: %s.%s", fnName, ident, mmbr)
- }
- }
- if len(elems) == 3 && !isExampleSuffix(elems[2]) {
- // Check ExampleFoo_Method_suffix and ExampleFoo_Method_Badsuffix.
- report("%s has malformed example suffix: %s", fnName, elems[2])
- }
-}
-
-func checkTest(fn *ast.FuncDecl, prefix string, report reporter) {
- // Want functions with 0 results and 1 parameter.
- if fn.Type.Results != nil && len(fn.Type.Results.List) > 0 ||
- fn.Type.Params == nil ||
- len(fn.Type.Params.List) != 1 ||
- len(fn.Type.Params.List[0].Names) > 1 {
- return
- }
-
- // The param must look like a *testing.T or *testing.B.
- if !isTestParam(fn.Type.Params.List[0].Type, prefix[:1]) {
- return
- }
-
- if !isTestSuffix(fn.Name.Name[len(prefix):]) {
- report("%s has malformed name: first letter after '%s' must not be lowercase", fn.Name.Name, prefix)
- }
-}
-
-type reporter func(format string, args ...interface{})
-
-// checkTestFunctions walks Test, Benchmark and Example functions checking
-// malformed names, wrong signatures and examples documenting nonexistent
-// identifiers.
-func checkTestFunctions(f *File, node ast.Node) {
- if !strings.HasSuffix(f.name, "_test.go") {
- return
- }
-
- fn, ok := node.(*ast.FuncDecl)
- if !ok || fn.Recv != nil {
- // Ignore non-functions or functions with receivers.
- return
- }
-
- report := func(format string, args ...interface{}) { f.Badf(node.Pos(), format, args...) }
-
- switch {
- case strings.HasPrefix(fn.Name.Name, "Example"):
- checkExample(fn, f, report)
- case strings.HasPrefix(fn.Name.Name, "Test"):
- checkTest(fn, "Test", report)
- case strings.HasPrefix(fn.Name.Name, "Benchmark"):
- checkTest(fn, "Benchmark", report)
- }
-}
diff --git a/libgo/go/cmd/vet/types.go b/libgo/go/cmd/vet/types.go
deleted file mode 100644
index 60b61250b85..00000000000
--- a/libgo/go/cmd/vet/types.go
+++ /dev/null
@@ -1,313 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file contains the pieces of the tool that use typechecking from the go/types package.
-
-package main
-
-import (
- "go/ast"
- "go/build"
- "go/importer"
- "go/token"
- "go/types"
-)
-
-// stdImporter is the importer we use to import packages.
-// It is shared so that all packages are imported by the same importer.
-var stdImporter types.Importer
-
-var (
- errorType *types.Interface
- stringerType *types.Interface // possibly nil
- formatterType *types.Interface // possibly nil
-)
-
-func inittypes() {
- errorType = types.Universe.Lookup("error").Type().Underlying().(*types.Interface)
-
- if typ := importType("fmt", "Stringer"); typ != nil {
- stringerType = typ.Underlying().(*types.Interface)
- }
- if typ := importType("fmt", "Formatter"); typ != nil {
- formatterType = typ.Underlying().(*types.Interface)
- }
-}
-
-// isNamedType reports whether t is the named type path.name.
-func isNamedType(t types.Type, path, name string) bool {
- n, ok := t.(*types.Named)
- if !ok {
- return false
- }
- obj := n.Obj()
- return obj.Name() == name && obj.Pkg() != nil && obj.Pkg().Path() == path
-}
-
-// importType returns the type denoted by the qualified identifier
-// path.name, and adds the respective package to the imports map
-// as a side effect. In case of an error, importType returns nil.
-func importType(path, name string) types.Type {
- pkg, err := stdImporter.Import(path)
- if err != nil {
- // This can happen if the package at path hasn't been compiled yet.
- warnf("import failed: %v", err)
- return nil
- }
- if obj, ok := pkg.Scope().Lookup(name).(*types.TypeName); ok {
- return obj.Type()
- }
- warnf("invalid type name %q", name)
- return nil
-}
-
-func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) []error {
- if stdImporter == nil {
- if *source {
- stdImporter = importer.For("source", nil)
- } else {
- stdImporter = importer.Default()
- }
- inittypes()
- }
- pkg.defs = make(map[*ast.Ident]types.Object)
- pkg.uses = make(map[*ast.Ident]types.Object)
- pkg.selectors = make(map[*ast.SelectorExpr]*types.Selection)
- pkg.spans = make(map[types.Object]Span)
- pkg.types = make(map[ast.Expr]types.TypeAndValue)
-
- var allErrors []error
- config := types.Config{
- // We use the same importer for all imports to ensure that
- // everybody sees identical packages for the given paths.
- Importer: stdImporter,
- // By providing a Config with our own error function, it will continue
- // past the first error. We collect them all for printing later.
- Error: func(e error) {
- allErrors = append(allErrors, e)
- },
-
- Sizes: archSizes,
- }
- info := &types.Info{
- Selections: pkg.selectors,
- Types: pkg.types,
- Defs: pkg.defs,
- Uses: pkg.uses,
- }
- typesPkg, err := config.Check(pkg.path, fs, astFiles, info)
- if len(allErrors) == 0 && err != nil {
- allErrors = append(allErrors, err)
- }
- pkg.typesPkg = typesPkg
- // update spans
- for id, obj := range pkg.defs {
- pkg.growSpan(id, obj)
- }
- for id, obj := range pkg.uses {
- pkg.growSpan(id, obj)
- }
- return allErrors
-}
-
-// matchArgType reports an error if printf verb t is not appropriate
-// for operand arg.
-//
-// typ is used only for recursive calls; external callers must supply nil.
-//
-// (Recursion arises from the compound types {map,chan,slice} which
-// may be printed with %d etc. if that is appropriate for their element
-// types.)
-func (f *File) matchArgType(t printfArgType, typ types.Type, arg ast.Expr) bool {
- return f.matchArgTypeInternal(t, typ, arg, make(map[types.Type]bool))
-}
-
-// matchArgTypeInternal is the internal version of matchArgType. It carries a map
-// remembering what types are in progress so we don't recur when faced with recursive
-// types or mutually recursive types.
-func (f *File) matchArgTypeInternal(t printfArgType, typ types.Type, arg ast.Expr, inProgress map[types.Type]bool) bool {
- // %v, %T accept any argument type.
- if t == anyType {
- return true
- }
- if typ == nil {
- // external call
- typ = f.pkg.types[arg].Type
- if typ == nil {
- return true // probably a type check problem
- }
- }
- // If the type implements fmt.Formatter, we have nothing to check.
- if f.isFormatter(typ) {
- return true
- }
- // If we can use a string, might arg (dynamically) implement the Stringer or Error interface?
- if t&argString != 0 && isConvertibleToString(typ) {
- return true
- }
-
- typ = typ.Underlying()
- if inProgress[typ] {
- // We're already looking at this type. The call that started it will take care of it.
- return true
- }
- inProgress[typ] = true
-
- switch typ := typ.(type) {
- case *types.Signature:
- return t&argPointer != 0
-
- case *types.Map:
- // Recur: map[int]int matches %d.
- return t&argPointer != 0 ||
- (f.matchArgTypeInternal(t, typ.Key(), arg, inProgress) && f.matchArgTypeInternal(t, typ.Elem(), arg, inProgress))
-
- case *types.Chan:
- return t&argPointer != 0
-
- case *types.Array:
- // Same as slice.
- if types.Identical(typ.Elem().Underlying(), types.Typ[types.Byte]) && t&argString != 0 {
- return true // %s matches []byte
- }
- // Recur: []int matches %d.
- return t&argPointer != 0 || f.matchArgTypeInternal(t, typ.Elem(), arg, inProgress)
-
- case *types.Slice:
- // Same as array.
- if types.Identical(typ.Elem().Underlying(), types.Typ[types.Byte]) && t&argString != 0 {
- return true // %s matches []byte
- }
- // Recur: []int matches %d. But watch out for
- // type T []T
- // If the element is a pointer type (type T[]*T), it's handled fine by the Pointer case below.
- return t&argPointer != 0 || f.matchArgTypeInternal(t, typ.Elem(), arg, inProgress)
-
- case *types.Pointer:
- // Ugly, but dealing with an edge case: a known pointer to an invalid type,
- // probably something from a failed import.
- if typ.Elem().String() == "invalid type" {
- if *verbose {
- f.Warnf(arg.Pos(), "printf argument %v is pointer to invalid or unknown type", f.gofmt(arg))
- }
- return true // special case
- }
- // If it's actually a pointer with %p, it prints as one.
- if t == argPointer {
- return true
- }
- // If it's pointer to struct, that's equivalent in our analysis to whether we can print the struct.
- if str, ok := typ.Elem().Underlying().(*types.Struct); ok {
- return f.matchStructArgType(t, str, arg, inProgress)
- }
- // Check whether the rest can print pointers.
- return t&argPointer != 0
-
- case *types.Struct:
- return f.matchStructArgType(t, typ, arg, inProgress)
-
- case *types.Interface:
- // There's little we can do.
- // Whether any particular verb is valid depends on the argument.
- // The user may have reasonable prior knowledge of the contents of the interface.
- return true
-
- case *types.Basic:
- switch typ.Kind() {
- case types.UntypedBool,
- types.Bool:
- return t&argBool != 0
-
- case types.UntypedInt,
- types.Int,
- types.Int8,
- types.Int16,
- types.Int32,
- types.Int64,
- types.Uint,
- types.Uint8,
- types.Uint16,
- types.Uint32,
- types.Uint64,
- types.Uintptr:
- return t&argInt != 0
-
- case types.UntypedFloat,
- types.Float32,
- types.Float64:
- return t&argFloat != 0
-
- case types.UntypedComplex,
- types.Complex64,
- types.Complex128:
- return t&argComplex != 0
-
- case types.UntypedString,
- types.String:
- return t&argString != 0
-
- case types.UnsafePointer:
- return t&(argPointer|argInt) != 0
-
- case types.UntypedRune:
- return t&(argInt|argRune) != 0
-
- case types.UntypedNil:
- return false
-
- case types.Invalid:
- if *verbose {
- f.Warnf(arg.Pos(), "printf argument %v has invalid or unknown type", f.gofmt(arg))
- }
- return true // Probably a type check problem.
- }
- panic("unreachable")
- }
-
- return false
-}
-
-func isConvertibleToString(typ types.Type) bool {
- if bt, ok := typ.(*types.Basic); ok && bt.Kind() == types.UntypedNil {
- // We explicitly don't want untyped nil, which is
- // convertible to both of the interfaces below, as it
- // would just panic anyway.
- return false
- }
- if types.ConvertibleTo(typ, errorType) {
- return true // via .Error()
- }
- if stringerType != nil && types.ConvertibleTo(typ, stringerType) {
- return true // via .String()
- }
- return false
-}
-
-// hasBasicType reports whether x's type is a types.Basic with the given kind.
-func (f *File) hasBasicType(x ast.Expr, kind types.BasicKind) bool {
- t := f.pkg.types[x].Type
- if t != nil {
- t = t.Underlying()
- }
- b, ok := t.(*types.Basic)
- return ok && b.Kind() == kind
-}
-
-// matchStructArgType reports whether all the elements of the struct match the expected
-// type. For instance, with "%d" all the elements must be printable with the "%d" format.
-func (f *File) matchStructArgType(t printfArgType, typ *types.Struct, arg ast.Expr, inProgress map[types.Type]bool) bool {
- for i := 0; i < typ.NumFields(); i++ {
- typf := typ.Field(i)
- if !f.matchArgTypeInternal(t, typf.Type(), arg, inProgress) {
- return false
- }
- if t&argString != 0 && !typf.Exported() && isConvertibleToString(typf.Type()) {
- // Issue #17798: unexported Stringer or error cannot be properly fomatted.
- return false
- }
- }
- return true
-}
-
-var archSizes = types.SizesFor(build.Default.Compiler, build.Default.GOARCH)
diff --git a/libgo/go/cmd/vet/unsafeptr.go b/libgo/go/cmd/vet/unsafeptr.go
deleted file mode 100644
index cb2cc818897..00000000000
--- a/libgo/go/cmd/vet/unsafeptr.go
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Check for invalid uintptr -> unsafe.Pointer conversions.
-
-package main
-
-import (
- "go/ast"
- "go/token"
- "go/types"
-)
-
-func init() {
- register("unsafeptr",
- "check for misuse of unsafe.Pointer",
- checkUnsafePointer,
- callExpr)
-}
-
-func checkUnsafePointer(f *File, node ast.Node) {
- x := node.(*ast.CallExpr)
- if len(x.Args) != 1 {
- return
- }
- if f.hasBasicType(x.Fun, types.UnsafePointer) && f.hasBasicType(x.Args[0], types.Uintptr) && !f.isSafeUintptr(x.Args[0]) {
- f.Badf(x.Pos(), "possible misuse of unsafe.Pointer")
- }
-}
-
-// isSafeUintptr reports whether x - already known to be a uintptr -
-// is safe to convert to unsafe.Pointer. It is safe if x is itself derived
-// directly from an unsafe.Pointer via conversion and pointer arithmetic
-// or if x is the result of reflect.Value.Pointer or reflect.Value.UnsafeAddr
-// or obtained from the Data field of a *reflect.SliceHeader or *reflect.StringHeader.
-func (f *File) isSafeUintptr(x ast.Expr) bool {
- switch x := x.(type) {
- case *ast.ParenExpr:
- return f.isSafeUintptr(x.X)
-
- case *ast.SelectorExpr:
- switch x.Sel.Name {
- case "Data":
- // reflect.SliceHeader and reflect.StringHeader are okay,
- // but only if they are pointing at a real slice or string.
- // It's not okay to do:
- // var x SliceHeader
- // x.Data = uintptr(unsafe.Pointer(...))
- // ... use x ...
- // p := unsafe.Pointer(x.Data)
- // because in the middle the garbage collector doesn't
- // see x.Data as a pointer and so x.Data may be dangling
- // by the time we get to the conversion at the end.
- // For now approximate by saying that *Header is okay
- // but Header is not.
- pt, ok := f.pkg.types[x.X].Type.(*types.Pointer)
- if ok {
- t, ok := pt.Elem().(*types.Named)
- if ok && t.Obj().Pkg().Path() == "reflect" {
- switch t.Obj().Name() {
- case "StringHeader", "SliceHeader":
- return true
- }
- }
- }
- }
-
- case *ast.CallExpr:
- switch len(x.Args) {
- case 0:
- // maybe call to reflect.Value.Pointer or reflect.Value.UnsafeAddr.
- sel, ok := x.Fun.(*ast.SelectorExpr)
- if !ok {
- break
- }
- switch sel.Sel.Name {
- case "Pointer", "UnsafeAddr":
- t, ok := f.pkg.types[sel.X].Type.(*types.Named)
- if ok && t.Obj().Pkg().Path() == "reflect" && t.Obj().Name() == "Value" {
- return true
- }
- }
-
- case 1:
- // maybe conversion of uintptr to unsafe.Pointer
- return f.hasBasicType(x.Fun, types.Uintptr) && f.hasBasicType(x.Args[0], types.UnsafePointer)
- }
-
- case *ast.BinaryExpr:
- switch x.Op {
- case token.ADD, token.SUB, token.AND_NOT:
- return f.isSafeUintptr(x.X) && !f.isSafeUintptr(x.Y)
- }
- }
- return false
-}
diff --git a/libgo/go/cmd/vet/unused.go b/libgo/go/cmd/vet/unused.go
deleted file mode 100644
index 02fcd841cd0..00000000000
--- a/libgo/go/cmd/vet/unused.go
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file defines the check for unused results of calls to certain
-// pure functions.
-
-package main
-
-import (
- "flag"
- "go/ast"
- "go/token"
- "go/types"
- "strings"
-)
-
-var unusedFuncsFlag = flag.String("unusedfuncs",
- "errors.New,fmt.Errorf,fmt.Sprintf,fmt.Sprint,sort.Reverse",
- "comma-separated list of functions whose results must be used")
-
-var unusedStringMethodsFlag = flag.String("unusedstringmethods",
- "Error,String",
- "comma-separated list of names of methods of type func() string whose results must be used")
-
-func init() {
- register("unusedresult",
- "check for unused result of calls to functions in -unusedfuncs list and methods in -unusedstringmethods list",
- checkUnusedResult,
- exprStmt)
-}
-
-// func() string
-var sigNoArgsStringResult = types.NewSignature(nil, nil,
- types.NewTuple(types.NewVar(token.NoPos, nil, "", types.Typ[types.String])),
- false)
-
-var unusedFuncs = make(map[string]bool)
-var unusedStringMethods = make(map[string]bool)
-
-func initUnusedFlags() {
- commaSplit := func(s string, m map[string]bool) {
- if s != "" {
- for _, name := range strings.Split(s, ",") {
- if len(name) == 0 {
- flag.Usage()
- }
- m[name] = true
- }
- }
- }
- commaSplit(*unusedFuncsFlag, unusedFuncs)
- commaSplit(*unusedStringMethodsFlag, unusedStringMethods)
-}
-
-func checkUnusedResult(f *File, n ast.Node) {
- call, ok := unparen(n.(*ast.ExprStmt).X).(*ast.CallExpr)
- if !ok {
- return // not a call statement
- }
- fun := unparen(call.Fun)
-
- if f.pkg.types[fun].IsType() {
- return // a conversion, not a call
- }
-
- selector, ok := fun.(*ast.SelectorExpr)
- if !ok {
- return // neither a method call nor a qualified ident
- }
-
- sel, ok := f.pkg.selectors[selector]
- if ok && sel.Kind() == types.MethodVal {
- // method (e.g. foo.String())
- obj := sel.Obj().(*types.Func)
- sig := sel.Type().(*types.Signature)
- if types.Identical(sig, sigNoArgsStringResult) {
- if unusedStringMethods[obj.Name()] {
- f.Badf(call.Lparen, "result of (%s).%s call not used",
- sig.Recv().Type(), obj.Name())
- }
- }
- } else if !ok {
- // package-qualified function (e.g. fmt.Errorf)
- obj := f.pkg.uses[selector.Sel]
- if obj, ok := obj.(*types.Func); ok {
- qname := obj.Pkg().Path() + "." + obj.Name()
- if unusedFuncs[qname] {
- f.Badf(call.Lparen, "result of %v call not used", qname)
- }
- }
- }
-}
diff --git a/libgo/go/cmd/vet/vet_test.go b/libgo/go/cmd/vet/vet_test.go
index 3e42525e89b..1c7b8625f35 100644
--- a/libgo/go/cmd/vet/vet_test.go
+++ b/libgo/go/cmd/vet/vet_test.go
@@ -60,120 +60,92 @@ func Build(t *testing.T) {
built = true
}
-func Vet(t *testing.T, files []string) {
- flags := []string{
- "-printfuncs=Warn:1,Warnf:1",
- "-all",
- "-shadow",
- }
- cmd := exec.Command(binary, append(flags, files...)...)
- errchk(cmd, files, t)
-}
-
-// TestVet is equivalent to running this:
-// go build -o ./testvet
-// errorCheck the output of ./testvet -shadow -printfuncs='Warn:1,Warnf:1' testdata/*.go testdata/*.s
-// rm ./testvet
-//
-
-// TestVet tests self-contained files in testdata/*.go.
-//
-// If a file contains assembly or has inter-dependencies, it should be
-// in its own test, like TestVetAsm, TestDivergentPackagesExamples,
-// etc below.
-func TestVet(t *testing.T) {
- Build(t)
- t.Parallel()
-
- gos, err := filepath.Glob(filepath.Join(dataDir, "*.go"))
- if err != nil {
- t.Fatal(err)
- }
- wide := runtime.GOMAXPROCS(0)
- if wide > len(gos) {
- wide = len(gos)
- }
- batch := make([][]string, wide)
- for i, file := range gos {
- // TODO: Remove print.go exception once we require type checking for everything,
- // and then delete TestVetPrint.
- if strings.HasSuffix(file, "print.go") {
- continue
- }
- batch[i%wide] = append(batch[i%wide], file)
- }
- for i, files := range batch {
- if len(files) == 0 {
- continue
- }
- files := files
- t.Run(fmt.Sprint(i), func(t *testing.T) {
- t.Parallel()
- t.Logf("files: %q", files)
- Vet(t, files)
- })
- }
-}
-
-func TestVetPrint(t *testing.T) {
- if runtime.Compiler == "gccgo" {
- // This test currently fails with gccgo because, in
- // the absence of standard library sources, gccgo can
- // not deduce that the standard log package formatting
- // functions are just printf wrappers.
- t.Skip("skipping for gccgo because there are no standard library sources")
- }
-
- Build(t)
- file := filepath.Join("testdata", "print.go")
- cmd := exec.Command(
- "go", "vet", "-vettool="+binary,
- "-printf",
- "-printfuncs=Warn:1,Warnf:1",
- file,
- )
- errchk(cmd, []string{file}, t)
-}
-
-func TestVetAsm(t *testing.T) {
- Build(t)
-
- asmDir := filepath.Join(dataDir, "asm")
- gos, err := filepath.Glob(filepath.Join(asmDir, "*.go"))
- if err != nil {
- t.Fatal(err)
- }
- asms, err := filepath.Glob(filepath.Join(asmDir, "*.s"))
+func vetCmd(t *testing.T, args ...string) *exec.Cmd {
+ cmd := exec.Command(testenv.GoToolPath(t), "vet", "-vettool="+binary)
+ cmd.Args = append(cmd.Args, args...)
+ testdata, err := filepath.Abs("testdata")
if err != nil {
t.Fatal(err)
}
-
- t.Parallel()
- Vet(t, append(gos, asms...))
+ cmd.Env = append(os.Environ(), "GOPATH="+testdata)
+ return cmd
}
-func TestVetDirs(t *testing.T) {
+func TestVet(t *testing.T) {
t.Parallel()
Build(t)
- for _, dir := range []string{
- "testingpkg",
- "divergent",
+ for _, pkg := range []string{
+ "asm",
+ "assign",
+ "atomic",
+ "bool",
"buildtag",
- "incomplete", // incomplete examples
"cgo",
+ "composite",
+ "copylock",
+ "deadcode",
+ "httpresponse",
+ "lostcancel",
+ "method",
+ "nilfunc",
+ "print",
+ "rangeloop",
+ "shift",
+ "structtag",
+ "testingpkg",
+ // "testtag" has its own test
+ "unmarshal",
+ "unsafeptr",
+ "unused",
} {
- dir := dir
- t.Run(dir, func(t *testing.T) {
+ pkg := pkg
+ t.Run(pkg, func(t *testing.T) {
t.Parallel()
- gos, err := filepath.Glob(filepath.Join("testdata", dir, "*.go"))
+
+ // Skip cgo test on platforms without cgo.
+ if pkg == "cgo" && !cgoEnabled(t) {
+ return
+ }
+
+ cmd := vetCmd(t, "-printfuncs=Warn,Warnf", pkg)
+
+ // The asm test assumes amd64.
+ if pkg == "asm" {
+ if runtime.Compiler == "gccgo" {
+ t.Skip("asm test assumes gc")
+ }
+ cmd.Env = append(cmd.Env, "GOOS=linux", "GOARCH=amd64")
+ }
+
+ dir := filepath.Join("testdata/src", pkg)
+ gos, err := filepath.Glob(filepath.Join(dir, "*.go"))
if err != nil {
t.Fatal(err)
}
- Vet(t, gos)
+ asms, err := filepath.Glob(filepath.Join(dir, "*.s"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ var files []string
+ files = append(files, gos...)
+ files = append(files, asms...)
+
+ errchk(cmd, files, t)
})
}
}
+func cgoEnabled(t *testing.T) bool {
+ // Don't trust build.Default.CgoEnabled as it is false for
+ // cross-builds unless CGO_ENABLED is explicitly specified.
+ // That's fine for the builders, but causes commands like
+ // 'GOARCH=386 go test .' to fail.
+ // Instead, we ask the go command.
+ cmd := exec.Command(testenv.GoToolPath(t), "list", "-f", "{{context.CgoEnabled}}")
+ out, _ := cmd.CombinedOutput()
+ return string(out) == "true\n"
+}
+
func errchk(c *exec.Cmd, files []string, t *testing.T) {
output, err := c.CombinedOutput()
if _, ok := err.(*exec.ExitError); !ok {
@@ -194,44 +166,35 @@ func errchk(c *exec.Cmd, files []string, t *testing.T) {
func TestTags(t *testing.T) {
t.Parallel()
Build(t)
- for _, tag := range []string{"testtag", "x testtag y", "x,testtag,y"} {
- tag := tag
+ for tag, wantFile := range map[string]int{
+ "testtag": 1, // file1
+ "x testtag y": 1,
+ "othertag": 2,
+ } {
+ tag, wantFile := tag, wantFile
t.Run(tag, func(t *testing.T) {
t.Parallel()
t.Logf("-tags=%s", tag)
- args := []string{
- "-tags=" + tag,
- "-v", // We're going to look at the files it examines.
- "testdata/tagtest",
- }
- cmd := exec.Command(binary, args...)
+ cmd := vetCmd(t, "-tags="+tag, "tagtest")
output, err := cmd.CombinedOutput()
- if err != nil {
- t.Fatal(err)
- }
+
+ want := fmt.Sprintf("file%d.go", wantFile)
+ dontwant := fmt.Sprintf("file%d.go", 3-wantFile)
+
// file1 has testtag and file2 has !testtag.
- if !bytes.Contains(output, []byte(filepath.Join("tagtest", "file1.go"))) {
- t.Error("file1 was excluded, should be included")
+ if !bytes.Contains(output, []byte(filepath.Join("tagtest", want))) {
+ t.Errorf("%s: %s was excluded, should be included", tag, want)
+ }
+ if bytes.Contains(output, []byte(filepath.Join("tagtest", dontwant))) {
+ t.Errorf("%s: %s was included, should be excluded", tag, dontwant)
}
- if bytes.Contains(output, []byte(filepath.Join("tagtest", "file2.go"))) {
- t.Error("file2 was included, should be excluded")
+ if t.Failed() {
+ t.Logf("err=%s, output=<<%s>>", err, output)
}
})
}
}
-// Issue #21188.
-func TestVetVerbose(t *testing.T) {
- t.Parallel()
- Build(t)
- cmd := exec.Command(binary, "-v", "-all", "testdata/cgo/cgo3.go")
- out, err := cmd.CombinedOutput()
- if err != nil {
- t.Logf("%s", out)
- t.Error(err)
- }
-}
-
// All declarations below were adapted from test/run.go.
// errorCheck matches errors in outStr against comments in source files.
@@ -241,10 +204,10 @@ func TestVetVerbose(t *testing.T) {
// this function will report an error.
// Likewise if outStr does not have an error for a line which has a comment,
// or if the error message does not match the <regexp>.
-// The <regexp> syntax is Perl but its best to stick to egrep.
+// The <regexp> syntax is Perl but it's best to stick to egrep.
//
// Sources files are supplied as fullshort slice.
-// It consists of pairs: full path to source file and it's base name.
+// It consists of pairs: full path to source file and its base name.
func errorCheck(outStr string, wantAuto bool, fullshort ...string) (err error) {
var errs []error
out := splitOutput(outStr, wantAuto)
@@ -252,7 +215,7 @@ func errorCheck(outStr string, wantAuto bool, fullshort ...string) (err error) {
for i := range out {
for j := 0; j < len(fullshort); j += 2 {
full, short := fullshort[j], fullshort[j+1]
- out[i] = strings.Replace(out[i], full, short, -1)
+ out[i] = strings.ReplaceAll(out[i], full, short)
}
}