diff --git a/doc/go1.12.html b/doc/go1.12.html index f4920f46703926..79f8eceb47e725 100644 --- a/doc/go1.12.html +++ b/doc/go1.12.html @@ -37,6 +37,16 @@
+ Go 1.12 is the last release that is supported on FreeBSD 10.x, which has + already reached end-of-life. Go 1.13 will require FreeBSD 11.2+ or FreeBSD + 12.0+. +
+<- operator specifies the channel direction,
send or receive. If no direction is given, the channel is
bidirectional.
-A channel may be constrained only to send or only to receive by explicit
-conversion or assignment.
+A channel may be constrained only to send or only to receive by
+assignment or
+explicit conversion.
@@ -3624,7 +3625,7 @@Integer overflow
-,*,/, and<<may legally overflow and the resulting value exists and is deterministically defined by the signed integer representation, the operation, and its operands. -Overflow does not cause a run-time panic. +Overflow does not cause a run-time panic. A compiler may not optimize code under the assumption that overflow does not occur. For instance, it may not assume thatx < x + 1is always true. diff --git a/misc/cgo/test/issue28545.go b/misc/cgo/test/issue28545.go index 802a20b779e6eb..0410a1662267da 100644 --- a/misc/cgo/test/issue28545.go +++ b/misc/cgo/test/issue28545.go @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. // Failed to add type conversion for negative constant. +// Issue 28772: Failed to add type conversion for Go constant set to C constant. // No runtime test; just make sure it compiles. package cgotest @@ -10,11 +11,16 @@ package cgotest /* #include+#define issue28772Constant 1 + static void issue28545F(char **p, int n, complex double a) {} */ import "C" +const issue28772Constant = C.issue28772Constant + func issue28545G(p **C.char) { C.issue28545F(p, -1, (0)) C.issue28545F(p, 2+3, complex(1, 1)) + C.issue28545F(p, issue28772Constant, (0)) } diff --git a/misc/cgo/testsanitizers/tsan_test.go b/misc/cgo/testsanitizers/tsan_test.go index 314b5072f360ee..1d769a98b6e26c 100644 --- a/misc/cgo/testsanitizers/tsan_test.go +++ b/misc/cgo/testsanitizers/tsan_test.go @@ -5,9 +5,9 @@ package sanitizers_test import ( + "runtime" "strings" "testing" - "runtime" ) func TestTSAN(t *testing.T) { diff --git a/misc/wasm/wasm_exec.js b/misc/wasm/wasm_exec.js index 440bba104c01df..83704a054f012a 100644 --- a/misc/wasm/wasm_exec.js +++ b/misc/wasm/wasm_exec.js @@ -442,7 +442,7 @@ const go = new Go(); go.argv = process.argv.slice(2); - go.env = process.env; + go.env = Object.assign({ TMPDIR: require("os").tmpdir() }, process.env); go.exit = process.exit; WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => { process.on("exit", (code) => { // Node.js exits if no callback is pending diff --git a/src/cmd/asm/doc.go b/src/cmd/asm/doc.go index c39cab3c195853..8bf0acac25f797 100644 --- a/src/cmd/asm/doc.go +++ b/src/cmd/asm/doc.go @@ -39,6 +39,8 @@ Flags: Generate code that can be linked into a shared library. -trimpath prefix Remove prefix from recorded source file paths. + -gensymabis + Write symbol ABI information to output file. Don't assemble. Input language: The assembler uses mostly the same syntax for all architectures, diff --git a/src/cmd/asm/internal/flags/flags.go b/src/cmd/asm/internal/flags/flags.go index 752a1d45265d3f..5fe3fd9d53c6f0 100644 --- a/src/cmd/asm/internal/flags/flags.go +++ b/src/cmd/asm/internal/flags/flags.go @@ -22,7 +22,7 @@ var ( Shared = flag.Bool("shared", false, "generate code that can be linked into a shared library") Dynlink = flag.Bool("dynlink", false, "support references to Go symbols defined in other shared libraries") AllErrors = flag.Bool("e", false, "no limit on number of errors reported") - SymABIs = flag.Bool("symabis", false, "write symbol ABI information to output file, don't assemble") + SymABIs = flag.Bool("gensymabis", false, "write symbol ABI information to output file, don't assemble") ) var ( diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go index 4462136bf4bc57..c342a017833b56 100644 --- a/src/cmd/cgo/ast.go +++ b/src/cmd/cgo/ast.go @@ -66,6 +66,7 @@ func (f *File) ParseGo(name string, src []byte) { f.Package = ast1.Name.Name f.Name = make(map[string]*Name) f.NamePos = make(map[*Name]token.Pos) + f.Consts = make(map[string]bool) // In ast1, find the import "C" line and get any extra C preamble. sawC := false @@ -191,6 +192,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 { + f.Consts[name.Name] = true + } + } + } + } + } } diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index 9b615db5db6dd0..fdd34f560fd711 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -1095,8 +1095,8 @@ func (p *Package) mangle(f *File, arg *ast.Expr) (ast.Expr, bool) { return *arg, needsUnsafe } -// checkIndex checks whether arg the form &a[i], possibly inside type -// conversions. If so, it writes +// 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 @@ -1135,7 +1135,7 @@ func (p *Package) checkIndex(sb, sbCheck *bytes.Buffer, arg ast.Expr, i int) boo } // checkAddr checks whether arg has the form &x, possibly inside type -// conversions. If so it writes +// conversions. If so, it writes // _cgoBaseNN := &x // _cgoNN := _cgoBaseNN // with type conversions, if any // to sb, and writes @@ -1232,7 +1232,8 @@ func (p *Package) isConst(f *File, x ast.Expr) bool { return x.Name == "nil" || strings.HasPrefix(x.Name, "_Ciconst_") || strings.HasPrefix(x.Name, "_Cfconst_") || - strings.HasPrefix(x.Name, "_Csconst_") + strings.HasPrefix(x.Name, "_Csconst_") || + f.Consts[x.Name] case *ast.UnaryExpr: return p.isConst(f, x.X) case *ast.BinaryExpr: diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go index 3098a4a63d3dcc..a317a1494d7824 100644 --- a/src/cmd/cgo/main.go +++ b/src/cmd/cgo/main.go @@ -62,6 +62,7 @@ type File struct { Name map[string]*Name // map from Go name to Name NamePos map[*Name]token.Pos // map from Name to position of the first reference Edit *edit.Buffer + Consts map[string]bool // untyped constants } func (f *File) offset(p token.Pos) int { diff --git a/src/cmd/compile/fmt_test.go b/src/cmd/compile/fmt_test.go index c5c050fa17c470..51079e3dcf21c3 100644 --- a/src/cmd/compile/fmt_test.go +++ b/src/cmd/compile/fmt_test.go @@ -9,18 +9,24 @@ // TestFormats finds potential (Printf, etc.) format strings. // If they are used in a call, the format verbs are verified // based on the matching argument type against a precomputed -// table of valid formats. The knownFormats table can be used -// to automatically rewrite format strings with the -u flag. +// map of valid formats (knownFormats). This map can be used to +// automatically rewrite format strings across all compiler +// files with the -r flag. // -// A new knownFormats table based on the found formats is printed -// when the test is run in verbose mode (-v flag). The table -// needs to be updated whenever a new (type, format) combination -// is found and the format verb is not 'v' or 'T' (as in "%v" or -// "%T"). +// The format map needs to be updated whenever a new (type, +// format) combination is found and the format verb is not +// 'v' or 'T' (as in "%v" or "%T"). To update the map auto- +// matically from the compiler source's use of format strings, +// use the -u flag. (Whether formats are valid for the values +// to be formatted must be verified manually, of course.) // -// Run as: go test -run Formats [-u][-v] +// The -v flag prints out the names of all functions called +// with a format string, the names of files that were not +// processed, and any format rewrites made (with -r). // -// Known bugs: +// Run as: go test -run Formats [-r][-u][-v] +// +// Known shortcomings: // - indexed format strings ("%[2]s", etc.) are not supported // (the test will fail) // - format strings that are not simple string literals cannot @@ -45,6 +51,7 @@ import ( "go/token" "go/types" "internal/testenv" + "io" "io/ioutil" "log" "os" @@ -56,7 +63,10 @@ import ( "unicode/utf8" ) -var update = flag.Bool("u", false, "update format strings") +var ( + rewrite = flag.Bool("r", false, "rewrite format strings") + update = flag.Bool("u", false, "update known formats") +) // The following variables collect information across all processed files. var ( @@ -173,11 +183,11 @@ func TestFormats(t *testing.T) { // write dirty files back var filesUpdated bool - if len(updatedFiles) > 0 && *update { + if len(updatedFiles) > 0 && *rewrite { for _, file := range updatedFiles { var buf bytes.Buffer if err := format.Node(&buf, fset, file.ast); err != nil { - t.Errorf("WARNING: formatting %s failed: %v", file.name, err) + t.Errorf("WARNING: gofmt %s failed: %v", file.name, err) continue } if err := ioutil.WriteFile(file.name, buf.Bytes(), 0x666); err != nil { @@ -189,7 +199,7 @@ func TestFormats(t *testing.T) { } } - // report all function names containing a format string + // report the names of all functions called with a format string if len(callSites) > 0 && testing.Verbose() { set := make(map[string]bool) for _, p := range callSites { @@ -199,23 +209,33 @@ func TestFormats(t *testing.T) { for s := range set { list = append(list, s) } - fmt.Println("\nFunctions") - printList(list) + fmt.Println("\nFunctions called with a format string") + writeList(os.Stdout, list) } - // report all formats found - if len(foundFormats) > 0 && testing.Verbose() { + // update formats + if len(foundFormats) > 0 && *update { var list []string for s := range foundFormats { list = append(list, fmt.Sprintf("%q: \"\",", s)) } - fmt.Println("\nvar knownFormats = map[string]string{") - printList(list) - fmt.Println("}") + var buf bytes.Buffer + buf.WriteString(knownFormatsHeader) + writeList(&buf, list) + buf.WriteString("}\n") + out, err := format.Source(buf.Bytes()) + const outfile = "fmtmap_test.go" + if err != nil { + t.Errorf("WARNING: gofmt %s failed: %v", outfile, err) + out = buf.Bytes() // continue with unformatted source + } + if err = ioutil.WriteFile(outfile, out, 0644); err != nil { + t.Errorf("WARNING: updating format map failed: %v", err) + } } // check that knownFormats is up to date - if !testing.Verbose() && !*update { + if !*rewrite && !*update { var mismatch bool for s := range foundFormats { if _, ok := knownFormats[s]; !ok { @@ -232,7 +252,7 @@ func TestFormats(t *testing.T) { } } if mismatch { - t.Errorf("knownFormats is out of date; please 'go test -v fmt_test.go > foo', then extract new definition of knownFormats from foo") + t.Errorf("format map is out of date; run 'go test -u' to update and manually verify correctness of change'") } } @@ -256,7 +276,7 @@ func TestFormats(t *testing.T) { list = append(list, fmt.Sprintf("%s: %s", posString(lit), nodeString(lit))) } fmt.Println("\nWARNING: Potentially missed format strings") - printList(list) + writeList(os.Stdout, list) t.Fail() } @@ -365,11 +385,11 @@ func collectPkgFormats(t *testing.T, pkg *build.Package) { } } -// printList prints list in sorted order. -func printList(list []string) { +// writeList writes list in sorted order to w. +func writeList(w io.Writer, list []string) { sort.Strings(list) for _, s := range list { - fmt.Println("\t", s) + fmt.Fprintln(w, "\t", s) } } @@ -542,7 +562,7 @@ func init() { // verify that knownFormats entries are correctly formatted for key, val := range knownFormats { // key must be "typename format", and format starts with a '%' - // (formats containing '*' alone are not collected in this table) + // (formats containing '*' alone are not collected in this map) i := strings.Index(key, "%") if i < 0 || !oneFormat(key[i:]) { log.Fatalf("incorrect knownFormats key: %q", key) @@ -554,189 +574,26 @@ func init() { } } +const knownFormatsHeader = `// 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 implements the knownFormats map which records the valid +// formats for a given type. The valid formats must correspond to +// supported compiler formats implemented in fmt.go, or whatever +// other format verbs are implemented for the given type. The map may +// also be used to change the use of a format verb across all compiler +// sources automatically (for instance, if the implementation of fmt.go +// changes), by using the -r option together with the new formats in the +// map. To generate this file automatically from the existing source, +// run: go test -run Formats -u. +// +// See the package comment in fmt_test.go for additional information. + +package main_test + // knownFormats entries are of the form "typename format" -> "newformat". // An absent entry means that the format is not recognized as valid. // An empty new format means that the format should remain unchanged. -// To print out a new table, run: go test -run Formats -v. var knownFormats = map[string]string{ - "*bytes.Buffer %s": "", - "*cmd/compile/internal/gc.Mpflt %v": "", - "*cmd/compile/internal/gc.Mpint %v": "", - "*cmd/compile/internal/gc.Node %#v": "", - "*cmd/compile/internal/gc.Node %+S": "", - "*cmd/compile/internal/gc.Node %+v": "", - "*cmd/compile/internal/gc.Node %0j": "", - "*cmd/compile/internal/gc.Node %L": "", - "*cmd/compile/internal/gc.Node %S": "", - "*cmd/compile/internal/gc.Node %j": "", - "*cmd/compile/internal/gc.Node %p": "", - "*cmd/compile/internal/gc.Node %v": "", - "*cmd/compile/internal/ssa.Block %s": "", - "*cmd/compile/internal/ssa.Block %v": "", - "*cmd/compile/internal/ssa.Func %s": "", - "*cmd/compile/internal/ssa.Func %v": "", - "*cmd/compile/internal/ssa.Register %s": "", - "*cmd/compile/internal/ssa.Register %v": "", - "*cmd/compile/internal/ssa.SparseTreeNode %v": "", - "*cmd/compile/internal/ssa.Value %s": "", - "*cmd/compile/internal/ssa.Value %v": "", - "*cmd/compile/internal/ssa.sparseTreeMapEntry %v": "", - "*cmd/compile/internal/types.Field %p": "", - "*cmd/compile/internal/types.Field %v": "", - "*cmd/compile/internal/types.Sym %0S": "", - "*cmd/compile/internal/types.Sym %S": "", - "*cmd/compile/internal/types.Sym %p": "", - "*cmd/compile/internal/types.Sym %v": "", - "*cmd/compile/internal/types.Type %#L": "", - "*cmd/compile/internal/types.Type %#v": "", - "*cmd/compile/internal/types.Type %+v": "", - "*cmd/compile/internal/types.Type %-S": "", - "*cmd/compile/internal/types.Type %0S": "", - "*cmd/compile/internal/types.Type %L": "", - "*cmd/compile/internal/types.Type %S": "", - "*cmd/compile/internal/types.Type %p": "", - "*cmd/compile/internal/types.Type %s": "", - "*cmd/compile/internal/types.Type %v": "", - "*cmd/internal/obj.Addr %v": "", - "*cmd/internal/obj.LSym %v": "", - "*math/big.Float %f": "", - "*math/big.Int %#x": "", - "*math/big.Int %s": "", - "*math/big.Int %v": "", - "[16]byte %x": "", - "[]*cmd/compile/internal/gc.Node %v": "", - "[]*cmd/compile/internal/ssa.Block %v": "", - "[]*cmd/compile/internal/ssa.Value %v": "", - "[][]string %q": "", - "[]byte %s": "", - "[]byte %x": "", - "[]cmd/compile/internal/ssa.Edge %v": "", - "[]cmd/compile/internal/ssa.ID %v": "", - "[]cmd/compile/internal/ssa.posetNode %v": "", - "[]cmd/compile/internal/ssa.posetUndo %v": "", - "[]cmd/compile/internal/syntax.token %s": "", - "[]string %v": "", - "[]uint32 %v": "", - "bool %v": "", - "byte %08b": "", - "byte %c": "", - "byte %v": "", - "cmd/compile/internal/arm.shift %d": "", - "cmd/compile/internal/gc.Class %d": "", - "cmd/compile/internal/gc.Class %s": "", - "cmd/compile/internal/gc.Class %v": "", - "cmd/compile/internal/gc.Ctype %d": "", - "cmd/compile/internal/gc.Ctype %v": "", - "cmd/compile/internal/gc.Level %d": "", - "cmd/compile/internal/gc.Level %v": "", - "cmd/compile/internal/gc.Nodes %#v": "", - "cmd/compile/internal/gc.Nodes %+v": "", - "cmd/compile/internal/gc.Nodes %.v": "", - "cmd/compile/internal/gc.Nodes %v": "", - "cmd/compile/internal/gc.Op %#v": "", - "cmd/compile/internal/gc.Op %v": "", - "cmd/compile/internal/gc.Val %#v": "", - "cmd/compile/internal/gc.Val %T": "", - "cmd/compile/internal/gc.Val %v": "", - "cmd/compile/internal/gc.fmtMode %d": "", - "cmd/compile/internal/gc.initKind %d": "", - "cmd/compile/internal/gc.itag %v": "", - "cmd/compile/internal/ssa.BranchPrediction %d": "", - "cmd/compile/internal/ssa.Edge %v": "", - "cmd/compile/internal/ssa.GCNode %v": "", - "cmd/compile/internal/ssa.ID %d": "", - "cmd/compile/internal/ssa.ID %v": "", - "cmd/compile/internal/ssa.LocPair %s": "", - "cmd/compile/internal/ssa.LocalSlot %s": "", - "cmd/compile/internal/ssa.LocalSlot %v": "", - "cmd/compile/internal/ssa.Location %T": "", - "cmd/compile/internal/ssa.Location %s": "", - "cmd/compile/internal/ssa.Op %s": "", - "cmd/compile/internal/ssa.Op %v": "", - "cmd/compile/internal/ssa.ValAndOff %s": "", - "cmd/compile/internal/ssa.domain %v": "", - "cmd/compile/internal/ssa.posetNode %v": "", - "cmd/compile/internal/ssa.posetTestOp %v": "", - "cmd/compile/internal/ssa.rbrank %d": "", - "cmd/compile/internal/ssa.regMask %d": "", - "cmd/compile/internal/ssa.register %d": "", - "cmd/compile/internal/syntax.Error %q": "", - "cmd/compile/internal/syntax.Expr %#v": "", - "cmd/compile/internal/syntax.Node %T": "", - "cmd/compile/internal/syntax.Operator %s": "", - "cmd/compile/internal/syntax.Pos %s": "", - "cmd/compile/internal/syntax.Pos %v": "", - "cmd/compile/internal/syntax.position %s": "", - "cmd/compile/internal/syntax.token %q": "", - "cmd/compile/internal/syntax.token %s": "", - "cmd/compile/internal/types.EType %d": "", - "cmd/compile/internal/types.EType %s": "", - "cmd/compile/internal/types.EType %v": "", - "cmd/internal/obj.ABI %v": "", - "error %v": "", - "float64 %.2f": "", - "float64 %.3f": "", - "float64 %.6g": "", - "float64 %g": "", - "int %-12d": "", - "int %-6d": "", - "int %-8o": "", - "int %02d": "", - "int %6d": "", - "int %c": "", - "int %d": "", - "int %v": "", - "int %x": "", - "int16 %d": "", - "int16 %x": "", - "int32 %d": "", - "int32 %v": "", - "int32 %x": "", - "int64 %+d": "", - "int64 %-10d": "", - "int64 %.5d": "", - "int64 %X": "", - "int64 %d": "", - "int64 %v": "", - "int64 %x": "", - "int8 %d": "", - "int8 %x": "", - "interface{} %#v": "", - "interface{} %T": "", - "interface{} %p": "", - "interface{} %q": "", - "interface{} %s": "", - "interface{} %v": "", - "map[*cmd/compile/internal/gc.Node]*cmd/compile/internal/ssa.Value %v": "", - "map[cmd/compile/internal/ssa.ID]uint32 %v": "", - "math/big.Accuracy %s": "", - "reflect.Type %s": "", - "rune %#U": "", - "rune %c": "", - "string %-*s": "", - "string %-16s": "", - "string %-6s": "", - "string %.*s": "", - "string %q": "", - "string %s": "", - "string %v": "", - "time.Duration %d": "", - "time.Duration %v": "", - "uint %04x": "", - "uint %5d": "", - "uint %d": "", - "uint %x": "", - "uint16 %d": "", - "uint16 %v": "", - "uint16 %x": "", - "uint32 %#x": "", - "uint32 %d": "", - "uint32 %v": "", - "uint32 %x": "", - "uint64 %08x": "", - "uint64 %d": "", - "uint64 %x": "", - "uint8 %d": "", - "uint8 %x": "", - "uintptr %d": "", -} +` diff --git a/src/cmd/compile/fmtmap_test.go b/src/cmd/compile/fmtmap_test.go new file mode 100644 index 00000000000000..063445cc9dcb28 --- /dev/null +++ b/src/cmd/compile/fmtmap_test.go @@ -0,0 +1,203 @@ +// 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 implements the knownFormats map which records the valid +// formats for a given type. The valid formats must correspond to +// supported compiler formats implemented in fmt.go, or whatever +// other format verbs are implemented for the given type. The map may +// also be used to change the use of a format verb across all compiler +// sources automatically (for instance, if the implementation of fmt.go +// changes), by using the -r option together with the new formats in the +// map. To generate this file automatically from the existing source, +// run: go test -run Formats -u. +// +// See the package comment in fmt_test.go for additional information. + +package main_test + +// knownFormats entries are of the form "typename format" -> "newformat". +// An absent entry means that the format is not recognized as valid. +// An empty new format means that the format should remain unchanged. +var knownFormats = map[string]string{ + "*bytes.Buffer %s": "", + "*cmd/compile/internal/gc.Mpflt %v": "", + "*cmd/compile/internal/gc.Mpint %v": "", + "*cmd/compile/internal/gc.Node %#v": "", + "*cmd/compile/internal/gc.Node %+S": "", + "*cmd/compile/internal/gc.Node %+v": "", + "*cmd/compile/internal/gc.Node %0j": "", + "*cmd/compile/internal/gc.Node %L": "", + "*cmd/compile/internal/gc.Node %S": "", + "*cmd/compile/internal/gc.Node %j": "", + "*cmd/compile/internal/gc.Node %p": "", + "*cmd/compile/internal/gc.Node %v": "", + "*cmd/compile/internal/ssa.Block %s": "", + "*cmd/compile/internal/ssa.Block %v": "", + "*cmd/compile/internal/ssa.Func %s": "", + "*cmd/compile/internal/ssa.Func %v": "", + "*cmd/compile/internal/ssa.Register %s": "", + "*cmd/compile/internal/ssa.Register %v": "", + "*cmd/compile/internal/ssa.SparseTreeNode %v": "", + "*cmd/compile/internal/ssa.Value %s": "", + "*cmd/compile/internal/ssa.Value %v": "", + "*cmd/compile/internal/ssa.sparseTreeMapEntry %v": "", + "*cmd/compile/internal/types.Field %p": "", + "*cmd/compile/internal/types.Field %v": "", + "*cmd/compile/internal/types.Sym %0S": "", + "*cmd/compile/internal/types.Sym %S": "", + "*cmd/compile/internal/types.Sym %p": "", + "*cmd/compile/internal/types.Sym %v": "", + "*cmd/compile/internal/types.Type %#L": "", + "*cmd/compile/internal/types.Type %#v": "", + "*cmd/compile/internal/types.Type %+v": "", + "*cmd/compile/internal/types.Type %-S": "", + "*cmd/compile/internal/types.Type %0S": "", + "*cmd/compile/internal/types.Type %L": "", + "*cmd/compile/internal/types.Type %S": "", + "*cmd/compile/internal/types.Type %p": "", + "*cmd/compile/internal/types.Type %s": "", + "*cmd/compile/internal/types.Type %v": "", + "*cmd/internal/obj.Addr %v": "", + "*cmd/internal/obj.LSym %v": "", + "*math/big.Float %f": "", + "*math/big.Int %#x": "", + "*math/big.Int %s": "", + "*math/big.Int %v": "", + "[16]byte %x": "", + "[]*cmd/compile/internal/gc.Node %v": "", + "[]*cmd/compile/internal/ssa.Block %v": "", + "[]*cmd/compile/internal/ssa.Value %v": "", + "[][]string %q": "", + "[]byte %s": "", + "[]byte %x": "", + "[]cmd/compile/internal/ssa.Edge %v": "", + "[]cmd/compile/internal/ssa.ID %v": "", + "[]cmd/compile/internal/ssa.posetNode %v": "", + "[]cmd/compile/internal/ssa.posetUndo %v": "", + "[]cmd/compile/internal/syntax.token %s": "", + "[]string %v": "", + "[]uint32 %v": "", + "bool %v": "", + "byte %08b": "", + "byte %c": "", + "byte %v": "", + "cmd/compile/internal/arm.shift %d": "", + "cmd/compile/internal/gc.Class %d": "", + "cmd/compile/internal/gc.Class %s": "", + "cmd/compile/internal/gc.Class %v": "", + "cmd/compile/internal/gc.Ctype %d": "", + "cmd/compile/internal/gc.Ctype %v": "", + "cmd/compile/internal/gc.Level %d": "", + "cmd/compile/internal/gc.Level %v": "", + "cmd/compile/internal/gc.Nodes %#v": "", + "cmd/compile/internal/gc.Nodes %+v": "", + "cmd/compile/internal/gc.Nodes %.v": "", + "cmd/compile/internal/gc.Nodes %v": "", + "cmd/compile/internal/gc.Op %#v": "", + "cmd/compile/internal/gc.Op %v": "", + "cmd/compile/internal/gc.Val %#v": "", + "cmd/compile/internal/gc.Val %T": "", + "cmd/compile/internal/gc.Val %v": "", + "cmd/compile/internal/gc.fmtMode %d": "", + "cmd/compile/internal/gc.initKind %d": "", + "cmd/compile/internal/gc.itag %v": "", + "cmd/compile/internal/ssa.BranchPrediction %d": "", + "cmd/compile/internal/ssa.Edge %v": "", + "cmd/compile/internal/ssa.GCNode %v": "", + "cmd/compile/internal/ssa.ID %d": "", + "cmd/compile/internal/ssa.ID %v": "", + "cmd/compile/internal/ssa.LocPair %s": "", + "cmd/compile/internal/ssa.LocalSlot %s": "", + "cmd/compile/internal/ssa.LocalSlot %v": "", + "cmd/compile/internal/ssa.Location %T": "", + "cmd/compile/internal/ssa.Location %s": "", + "cmd/compile/internal/ssa.Op %s": "", + "cmd/compile/internal/ssa.Op %v": "", + "cmd/compile/internal/ssa.ValAndOff %s": "", + "cmd/compile/internal/ssa.domain %v": "", + "cmd/compile/internal/ssa.posetNode %v": "", + "cmd/compile/internal/ssa.posetTestOp %v": "", + "cmd/compile/internal/ssa.rbrank %d": "", + "cmd/compile/internal/ssa.regMask %d": "", + "cmd/compile/internal/ssa.register %d": "", + "cmd/compile/internal/syntax.Error %q": "", + "cmd/compile/internal/syntax.Expr %#v": "", + "cmd/compile/internal/syntax.Node %T": "", + "cmd/compile/internal/syntax.Operator %s": "", + "cmd/compile/internal/syntax.Pos %s": "", + "cmd/compile/internal/syntax.Pos %v": "", + "cmd/compile/internal/syntax.position %s": "", + "cmd/compile/internal/syntax.token %q": "", + "cmd/compile/internal/syntax.token %s": "", + "cmd/compile/internal/types.EType %d": "", + "cmd/compile/internal/types.EType %s": "", + "cmd/compile/internal/types.EType %v": "", + "cmd/internal/obj.ABI %v": "", + "error %v": "", + "float64 %.2f": "", + "float64 %.3f": "", + "float64 %.6g": "", + "float64 %g": "", + "int %-12d": "", + "int %-6d": "", + "int %-8o": "", + "int %02d": "", + "int %6d": "", + "int %c": "", + "int %d": "", + "int %v": "", + "int %x": "", + "int16 %d": "", + "int16 %x": "", + "int32 %d": "", + "int32 %v": "", + "int32 %x": "", + "int64 %+d": "", + "int64 %-10d": "", + "int64 %.5d": "", + "int64 %X": "", + "int64 %d": "", + "int64 %v": "", + "int64 %x": "", + "int8 %d": "", + "int8 %x": "", + "interface{} %#v": "", + "interface{} %T": "", + "interface{} %p": "", + "interface{} %q": "", + "interface{} %s": "", + "interface{} %v": "", + "map[*cmd/compile/internal/gc.Node]*cmd/compile/internal/ssa.Value %v": "", + "map[cmd/compile/internal/ssa.ID]uint32 %v": "", + "math/big.Accuracy %s": "", + "reflect.Type %s": "", + "rune %#U": "", + "rune %c": "", + "string %-*s": "", + "string %-16s": "", + "string %-6s": "", + "string %.*s": "", + "string %q": "", + "string %s": "", + "string %v": "", + "time.Duration %d": "", + "time.Duration %v": "", + "uint %04x": "", + "uint %5d": "", + "uint %d": "", + "uint %x": "", + "uint16 %d": "", + "uint16 %v": "", + "uint16 %x": "", + "uint32 %#x": "", + "uint32 %d": "", + "uint32 %v": "", + "uint32 %x": "", + "uint64 %08x": "", + "uint64 %d": "", + "uint64 %x": "", + "uint8 %d": "", + "uint8 %x": "", + "uintptr %d": "", +} diff --git a/src/cmd/compile/internal/gc/alg.go b/src/cmd/compile/internal/gc/alg.go index f52c15b1f5c3cf..2710e04f40f255 100644 --- a/src/cmd/compile/internal/gc/alg.go +++ b/src/cmd/compile/internal/gc/alg.go @@ -217,7 +217,7 @@ func genhash(sym *types.Sym, t *types.Type) { // pure memory. hashel := hashfor(t.Elem()) - n := nod(ORANGE, nil, nod(OIND, np, nil)) + n := nod(ORANGE, nil, nod(ODEREF, np, nil)) ni := newname(lookup("i")) ni.Type = types.Types[TINT] n.List.Set1(ni) @@ -290,10 +290,10 @@ func genhash(sym *types.Sym, t *types.Type) { funcbody() fn.Func.SetDupok(true) - fn = typecheck(fn, Etop) + fn = typecheck(fn, ctxStmt) Curfn = fn - typecheckslice(fn.Nbody.Slice(), Etop) + typecheckslice(fn.Nbody.Slice(), ctxStmt) Curfn = nil if debug_dclstack != 0 { @@ -375,7 +375,7 @@ func geneq(sym *types.Sym, t *types.Type) { // pure memory. Even if we unrolled the range loop, // each iteration would be a function call, so don't bother // unrolling. - nrange := nod(ORANGE, nil, nod(OIND, np, nil)) + nrange := nod(ORANGE, nil, nod(ODEREF, np, nil)) ni := newname(lookup("i")) ni.Type = types.Types[TINT] @@ -465,10 +465,10 @@ func geneq(sym *types.Sym, t *types.Type) { funcbody() fn.Func.SetDupok(true) - fn = typecheck(fn, Etop) + fn = typecheck(fn, ctxStmt) Curfn = fn - typecheckslice(fn.Nbody.Slice(), Etop) + typecheckslice(fn.Nbody.Slice(), ctxStmt) Curfn = nil if debug_dclstack != 0 { @@ -497,8 +497,8 @@ func eqfield(p *Node, q *Node, field *types.Sym) *Node { func eqmem(p *Node, q *Node, field *types.Sym, size int64) *Node { nx := nod(OADDR, nodSym(OXDOT, p, field), nil) ny := nod(OADDR, nodSym(OXDOT, q, field), nil) - nx = typecheck(nx, Erv) - ny = typecheck(ny, Erv) + nx = typecheck(nx, ctxExpr) + ny = typecheck(ny, ctxExpr) fn, needsize := eqmemfunc(size, nx.Type.Elem()) call := nod(OCALL, fn, nil) diff --git a/src/cmd/compile/internal/gc/closure.go b/src/cmd/compile/internal/gc/closure.go index 5123df8e9d15f0..07064415f499ea 100644 --- a/src/cmd/compile/internal/gc/closure.go +++ b/src/cmd/compile/internal/gc/closure.go @@ -93,7 +93,7 @@ func typecheckclosure(clo *Node, top int) { xfunc.Func.Nname.Sym = closurename(Curfn) disableExport(xfunc.Func.Nname.Sym) declare(xfunc.Func.Nname, PFUNC) - xfunc = typecheck(xfunc, Etop) + xfunc = typecheck(xfunc, ctxStmt) clo.Func.Ntype = typecheck(clo.Func.Ntype, Etype) clo.Type = clo.Func.Ntype.Type @@ -108,7 +108,7 @@ func typecheckclosure(clo *Node, top int) { Curfn = xfunc olddd := decldepth decldepth = 1 - typecheckslice(xfunc.Nbody.Slice(), Etop) + typecheckslice(xfunc.Nbody.Slice(), ctxStmt) decldepth = olddd Curfn = oldfn } @@ -199,7 +199,7 @@ func capturevars(xfunc *Node) { Warnl(v.Pos, "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym, outermost.Addrtaken(), outermost.Assigned(), int32(v.Type.Width)) } - outer = typecheck(outer, Erv) + outer = typecheck(outer, ctxExpr) clo.Func.Enter.Append(outer) } @@ -214,7 +214,7 @@ func transformclosure(xfunc *Node) { lineno = xfunc.Pos clo := xfunc.Func.Closure - if clo.Func.Top&Ecall != 0 { + if clo.Func.Top&ctxCallee != 0 { // If the closure is directly called, we transform it to a plain function call // with variables passed as args. This avoids allocation of a closure object. // Here we do only a part of the transformation. Walk of OCALLFUNC(OCLOSURE) @@ -305,7 +305,7 @@ func transformclosure(xfunc *Node) { } if len(body) > 0 { - typecheckslice(body, Etop) + typecheckslice(body, ctxStmt) xfunc.Func.Enter.Set(body) xfunc.Func.SetNeedctxt(true) } @@ -383,7 +383,7 @@ func walkclosure(clo *Node, init *Nodes) *Node { typ := closureType(clo) - clos := nod(OCOMPLIT, nil, nod(OIND, typenod(typ), nil)) + clos := nod(OCOMPLIT, nil, nod(ODEREF, typenod(typ), nil)) clos.Esc = clo.Esc clos.Right.SetImplicit(true) clos.List.Set(append([]*Node{nod(OCFUNC, xfunc.Func.Nname, nil)}, clo.Func.Enter.Slice()...)) @@ -467,7 +467,7 @@ func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node { call := nod(OCALL, nodSym(OXDOT, ptr, meth), nil) call.List.Set(paramNnames(tfn.Type)) - call.SetIsddd(tfn.Type.IsVariadic()) + call.SetIsDDD(tfn.Type.IsVariadic()) if t0.NumResults() != 0 { n := nod(ORETURN, nil, nil) n.List.Set1(call) @@ -478,7 +478,7 @@ func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node { xfunc.Nbody.Set(body) funcbody() - xfunc = typecheck(xfunc, Etop) + xfunc = typecheck(xfunc, ctxStmt) sym.Def = asTypesNode(xfunc) xtop = append(xtop, xfunc) Curfn = savecurfn @@ -516,7 +516,7 @@ func walkpartialcall(n *Node, init *Nodes) *Node { typ := partialCallType(n) - clos := nod(OCOMPLIT, nil, nod(OIND, typenod(typ), nil)) + clos := nod(OCOMPLIT, nil, nod(ODEREF, typenod(typ), nil)) clos.Esc = n.Esc clos.Right.SetImplicit(true) clos.List.Set2(nod(OCFUNC, n.Func.Nname, nil), n.Left) diff --git a/src/cmd/compile/internal/gc/const.go b/src/cmd/compile/internal/gc/const.go index a77759832a32a2..9f5afadd70dfaa 100644 --- a/src/cmd/compile/internal/gc/const.go +++ b/src/cmd/compile/internal/gc/const.go @@ -588,7 +588,7 @@ func evconst(n *Node) { // Pick off just the opcodes that can be constant evaluated. switch op := n.Op; op { - case OPLUS, OMINUS, OCOM, ONOT: + case OPLUS, ONEG, OBITNOT, ONOT: if nl.Op == OLITERAL { setconst(n, unaryOp(op, nl.Val(), n.Type)) } @@ -623,7 +623,7 @@ func evconst(n *Node) { setconst(n, convlit1(nl, n.Type, true, false).Val()) } - case OARRAYBYTESTR: + case OBYTES2STR: // string([]byte(nil)) or string([]rune(nil)) if nl.Op == OLITERAL && nl.Val().Ctype() == CTNIL { setconst(n, Val{U: ""}) @@ -873,7 +873,7 @@ func unaryOp(op Op, x Val, t *types.Type) Val { return x } - case OMINUS: + case ONEG: switch x.Ctype() { case CTINT, CTRUNE: x := x.U.(*Mpint) @@ -900,7 +900,7 @@ func unaryOp(op Op, x Val, t *types.Type) Val { return Val{U: u} } - case OCOM: + case OBITNOT: x := x.U.(*Mpint) u := new(Mpint) @@ -1024,9 +1024,9 @@ func idealkind(n *Node) Ctype { case OADD, OAND, OANDNOT, - OCOM, + OBITNOT, ODIV, - OMINUS, + ONEG, OMOD, OMUL, OSUB, @@ -1281,7 +1281,7 @@ func (n *Node) isGoConst() bool { OAND, OANDAND, OANDNOT, - OCOM, + OBITNOT, ODIV, OEQ, OGE, @@ -1289,7 +1289,7 @@ func (n *Node) isGoConst() bool { OLE, OLSH, OLT, - OMINUS, + ONEG, OMOD, OMUL, ONE, diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go index d4d0708b1c876c..9f25e5e15ba26f 100644 --- a/src/cmd/compile/internal/gc/dcl.go +++ b/src/cmd/compile/internal/gc/dcl.go @@ -283,7 +283,7 @@ func oldname(s *types.Sym) *Node { c = newname(s) c.SetClass(PAUTOHEAP) c.SetIsClosureVar(true) - c.SetIsddd(n.Isddd()) + c.SetIsDDD(n.IsDDD()) c.Name.Defn = n c.SetAddable(false) @@ -455,7 +455,7 @@ func funcarg(n *Node, ctxt Class) { n.Right = newnamel(n.Pos, n.Sym) n.Right.Name.Param.Ntype = n.Left - n.Right.SetIsddd(n.Isddd()) + n.Right.SetIsDDD(n.IsDDD()) declare(n.Right, ctxt) vargen++ @@ -488,7 +488,7 @@ func funcarg2(f *types.Field, ctxt Class) { n := newnamel(f.Pos, f.Sym) f.Nname = asTypesNode(n) n.Type = f.Type - n.SetIsddd(f.Isddd()) + n.SetIsDDD(f.IsDDD()) declare(n, ctxt) } @@ -628,7 +628,7 @@ func tofunargs(l []*Node, funarg types.Funarg) *types.Type { fields := make([]*types.Field, len(l)) for i, n := range l { f := structfield(n) - f.SetIsddd(n.Isddd()) + f.SetIsDDD(n.IsDDD()) if n.Right != nil { n.Right.Type = f.Type f.Nname = asTypesNode(n.Right) diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go index 2310b1e5fd2e91..c003964fa74665 100644 --- a/src/cmd/compile/internal/gc/esc.go +++ b/src/cmd/compile/internal/gc/esc.go @@ -671,7 +671,7 @@ func (e *EscState) isSliceSelfAssign(dst, src *Node) bool { // when we evaluate it for dst and for src. // dst is ONAME dereference. - if dst.Op != OIND && dst.Op != ODOTPTR || dst.Left.Op != ONAME { + if dst.Op != ODEREF && dst.Op != ODOTPTR || dst.Left.Op != ONAME { return false } // src is a slice operation. @@ -695,7 +695,7 @@ func (e *EscState) isSliceSelfAssign(dst, src *Node) bool { return false } // slice is applied to ONAME dereference. - if src.Left.Op != OIND && src.Left.Op != ODOTPTR || src.Left.Left.Op != ONAME { + if src.Left.Op != ODEREF && src.Left.Op != ODOTPTR || src.Left.Left.Op != ONAME { return false } // dst and src reference the same base ONAME. @@ -757,8 +757,8 @@ func (e *EscState) mayAffectMemory(n *Node) bool { return e.mayAffectMemory(n.Left) || e.mayAffectMemory(n.Right) // Left group. - case ODOT, ODOTPTR, OIND, OCONVNOP, OCONV, OLEN, OCAP, - ONOT, OCOM, OPLUS, OMINUS, OALIGNOF, OOFFSETOF, OSIZEOF: + case ODOT, ODOTPTR, ODEREF, OCONVNOP, OCONV, OLEN, OCAP, + ONOT, OBITNOT, OPLUS, ONEG, OALIGNOF, OOFFSETOF, OSIZEOF: return e.mayAffectMemory(n.Left) default: @@ -935,7 +935,7 @@ opSwitch: e.escassignSinkWhy(n, arg, "defer func arg") } - case OPROC: + case OGO: // go f(x) - f and x escape e.escassignSinkWhy(n, n.Left.Left, "go func") e.escassignSinkWhy(n, n.Left.Right, "go func ...") // ODDDARG for call @@ -991,7 +991,7 @@ opSwitch: e.escassignSinkWhy(n, n.Left, "panic") case OAPPEND: - if !n.Isddd() { + if !n.IsDDD() { for _, nn := range n.List.Slice()[1:] { e.escassignSinkWhy(n, nn, "appended to slice") // lose track of assign to dereference } @@ -1072,7 +1072,7 @@ opSwitch: a = nod(OADDR, a, nil) a.Pos = v.Pos e.nodeEscState(a).Loopdepth = e.loopdepth - a = typecheck(a, Erv) + a = typecheck(a, ctxExpr) } e.escassignWhyWhere(n, a, "captured by a closure", n) @@ -1083,10 +1083,10 @@ opSwitch: OMAKEMAP, OMAKESLICE, ONEW, - OARRAYRUNESTR, - OARRAYBYTESTR, - OSTRARRAYRUNE, - OSTRARRAYBYTE, + ORUNES2STR, + OBYTES2STR, + OSTR2RUNES, + OSTR2BYTES, ORUNESTR: e.track(n) @@ -1223,7 +1223,7 @@ func (e *EscState) escassign(dst, src *Node, step *EscStep) { dstwhy = "slice-element-equals" dst = &e.theSink // lose track of dereference - case OIND: + case ODEREF: dstwhy = "star-equals" dst = &e.theSink // lose track of dereference @@ -1243,7 +1243,7 @@ func (e *EscState) escassign(dst, src *Node, step *EscStep) { switch src.Op { case OADDR, // dst = &x - OIND, // dst = *x + ODEREF, // dst = *x ODOTPTR, // dst = (*x).f ONAME, ODDDARG, @@ -1255,10 +1255,10 @@ func (e *EscState) escassign(dst, src *Node, step *EscStep) { OMAKECHAN, OMAKEMAP, OMAKESLICE, - OARRAYRUNESTR, - OARRAYBYTESTR, - OSTRARRAYRUNE, - OSTRARRAYBYTE, + ORUNES2STR, + OBYTES2STR, + OSTR2RUNES, + OSTR2BYTES, OADDSTR, ONEW, OCALLPART, @@ -1293,7 +1293,7 @@ func (e *EscState) escassign(dst, src *Node, step *EscStep) { case OCONV, OCONVNOP, ODOTMETH, - // treat recv.meth as a value with recv in it, only happens in ODEFER and OPROC + // treat recv.meth as a value with recv in it, only happens in ODEFER and OGO // iface.method already leaks iface in esccall, no need to put in extra ODOTINTER edge here OSLICE, OSLICE3, @@ -1338,8 +1338,8 @@ func (e *EscState) escassign(dst, src *Node, step *EscStep) { OAND, OANDNOT, OPLUS, - OMINUS, - OCOM: + ONEG, + OBITNOT: e.escassign(dst, src.Left, e.stepAssign(step, originalDst, src, dstwhy)) e.escassign(dst, src.Right, e.stepAssign(step, originalDst, src, dstwhy)) @@ -1500,16 +1500,16 @@ func (e *EscState) escassignDereference(dst *Node, src *Node, step *EscStep) { e.escassign(dst, e.addDereference(src), step) } -// addDereference constructs a suitable OIND note applied to src. +// addDereference constructs a suitable ODEREF note applied to src. // Because this is for purposes of escape accounting, not execution, // some semantically dubious node combinations are (currently) possible. func (e *EscState) addDereference(n *Node) *Node { - ind := nod(OIND, n, nil) + ind := nod(ODEREF, n, nil) e.nodeEscState(ind).Loopdepth = e.nodeEscState(n).Loopdepth ind.Pos = n.Pos t := n.Type if t.IsPtr() || t.IsSlice() { - // This should model our own sloppy use of OIND to encode + // This should model our own sloppy use of ODEREF to encode // decreasing levels of indirection; i.e., "indirecting" a slice // yields the type of an element. t = t.Elem() @@ -1665,7 +1665,7 @@ func (e *EscState) esccall(call *Node, parent *Node) { continue } arg := args[0] - if n.Isddd() && !call.Isddd() { + if n.IsDDD() && !call.IsDDD() { // Introduce ODDDARG node to represent ... allocation. arg = nod(ODDDARG, nil, nil) arr := types.NewArray(n.Type.Elem(), int64(len(args))) @@ -1722,7 +1722,7 @@ func (e *EscState) esccall(call *Node, parent *Node) { for i, param := range fntype.Params().FieldSlice() { note := param.Note var arg *Node - if param.Isddd() && !call.Isddd() { + if param.IsDDD() && !call.IsDDD() { rest := args[i:] if len(rest) == 0 { break @@ -1754,7 +1754,7 @@ func (e *EscState) esccall(call *Node, parent *Node) { } } - if types.Haspointers(param.Type) && e.escassignfromtag(note, cE.Retval, arg, call)&EscMask == EscNone && parent.Op != ODEFER && parent.Op != OPROC { + if types.Haspointers(param.Type) && e.escassignfromtag(note, cE.Retval, arg, call)&EscMask == EscNone && parent.Op != ODEFER && parent.Op != OGO { a := arg for a.Op == OCONVNOP { a = a.Left @@ -2057,10 +2057,10 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep, case OMAKECHAN, OMAKEMAP, OMAKESLICE, - OARRAYRUNESTR, - OARRAYBYTESTR, - OSTRARRAYRUNE, - OSTRARRAYBYTE, + ORUNES2STR, + OBYTES2STR, + OSTR2RUNES, + OSTR2BYTES, OADDSTR, OMAPLIT, ONEW, @@ -2100,7 +2100,7 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep, e.escwalk(level.inc(), dst, src.Left, e.stepWalk(dst, src.Left, "dot of pointer", step)) case OINDEXMAP: e.escwalk(level.inc(), dst, src.Left, e.stepWalk(dst, src.Left, "map index", step)) - case OIND: + case ODEREF: e.escwalk(level.inc(), dst, src.Left, e.stepWalk(dst, src.Left, "indirection", step)) // In this case a link went directly to a call, but should really go @@ -2142,7 +2142,7 @@ func addrescapes(n *Node) { default: // Unexpected Op, probably due to a previous type error. Ignore. - case OIND, ODOTPTR: + case ODEREF, ODOTPTR: // Nothing to do. case ONAME: @@ -2347,7 +2347,7 @@ func (e *EscState) esctag(fn *Node) { f.Note = uintptrEscapesTag } - if f.Isddd() && f.Type.Elem().Etype == TUINTPTR { + if f.IsDDD() && f.Type.Elem().Etype == TUINTPTR { // final argument is ...uintptr. if Debug['m'] != 0 { Warnl(fn.Pos, "%v marking %v as escaping ...uintptr", funcSym(fn), name(f.Sym, narg)) diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go index 16b81e6a88df62..36f7545b3ca0f1 100644 --- a/src/cmd/compile/internal/gc/fmt.go +++ b/src/cmd/compile/internal/gc/fmt.go @@ -159,7 +159,7 @@ var goopnames = []string{ OCASE: "case", OCLOSE: "close", OCOMPLEX: "complex", - OCOM: "^", + OBITNOT: "^", OCONTINUE: "continue", OCOPY: "copy", ODELETE: "delete", @@ -174,13 +174,13 @@ var goopnames = []string{ OGT: ">", OIF: "if", OIMAG: "imag", - OIND: "*", + ODEREF: "*", OLEN: "len", OLE: "<=", OLSH: "<<", OLT: "<", OMAKE: "make", - OMINUS: "-", + ONEG: "-", OMOD: "%", OMUL: "*", ONEW: "new", @@ -464,8 +464,8 @@ func (n *Node) jconv(s fmt.State, flag FmtFlag) { fmt.Fprintf(s, " tc(%d)", n.Typecheck()) } - if n.Isddd() { - fmt.Fprintf(s, " isddd(%v)", n.Isddd()) + if n.IsDDD() { + fmt.Fprintf(s, " isddd(%v)", n.IsDDD()) } if n.Implicit() { @@ -942,7 +942,7 @@ func (n *Node) stmtfmt(s fmt.State, mode fmtMode) { case ORETJMP: mode.Fprintf(s, "retjmp %v", n.Sym) - case OPROC: + case OGO: mode.Fprintf(s, "go %v", n.Left) case ODEFER: @@ -1064,92 +1064,92 @@ func (n *Node) stmtfmt(s fmt.State, mode fmtMode) { } var opprec = []int{ - OALIGNOF: 8, - OAPPEND: 8, - OARRAYBYTESTR: 8, - OARRAYLIT: 8, - OSLICELIT: 8, - OARRAYRUNESTR: 8, - OCALLFUNC: 8, - OCALLINTER: 8, - OCALLMETH: 8, - OCALL: 8, - OCAP: 8, - OCLOSE: 8, - OCONVIFACE: 8, - OCONVNOP: 8, - OCONV: 8, - OCOPY: 8, - ODELETE: 8, - OGETG: 8, - OLEN: 8, - OLITERAL: 8, - OMAKESLICE: 8, - OMAKE: 8, - OMAPLIT: 8, - ONAME: 8, - ONEW: 8, - ONONAME: 8, - OOFFSETOF: 8, - OPACK: 8, - OPANIC: 8, - OPAREN: 8, - OPRINTN: 8, - OPRINT: 8, - ORUNESTR: 8, - OSIZEOF: 8, - OSTRARRAYBYTE: 8, - OSTRARRAYRUNE: 8, - OSTRUCTLIT: 8, - OTARRAY: 8, - OTCHAN: 8, - OTFUNC: 8, - OTINTER: 8, - OTMAP: 8, - OTSTRUCT: 8, - OINDEXMAP: 8, - OINDEX: 8, - OSLICE: 8, - OSLICESTR: 8, - OSLICEARR: 8, - OSLICE3: 8, - OSLICE3ARR: 8, - OSLICEHEADER: 8, - ODOTINTER: 8, - ODOTMETH: 8, - ODOTPTR: 8, - ODOTTYPE2: 8, - ODOTTYPE: 8, - ODOT: 8, - OXDOT: 8, - OCALLPART: 8, - OPLUS: 7, - ONOT: 7, - OCOM: 7, - OMINUS: 7, - OADDR: 7, - OIND: 7, - ORECV: 7, - OMUL: 6, - ODIV: 6, - OMOD: 6, - OLSH: 6, - ORSH: 6, - OAND: 6, - OANDNOT: 6, - OADD: 5, - OSUB: 5, - OOR: 5, - OXOR: 5, - OEQ: 4, - OLT: 4, - OLE: 4, - OGE: 4, - OGT: 4, - ONE: 4, - OSEND: 3, - OANDAND: 2, - OOROR: 1, + OALIGNOF: 8, + OAPPEND: 8, + OBYTES2STR: 8, + OARRAYLIT: 8, + OSLICELIT: 8, + ORUNES2STR: 8, + OCALLFUNC: 8, + OCALLINTER: 8, + OCALLMETH: 8, + OCALL: 8, + OCAP: 8, + OCLOSE: 8, + OCONVIFACE: 8, + OCONVNOP: 8, + OCONV: 8, + OCOPY: 8, + ODELETE: 8, + OGETG: 8, + OLEN: 8, + OLITERAL: 8, + OMAKESLICE: 8, + OMAKE: 8, + OMAPLIT: 8, + ONAME: 8, + ONEW: 8, + ONONAME: 8, + OOFFSETOF: 8, + OPACK: 8, + OPANIC: 8, + OPAREN: 8, + OPRINTN: 8, + OPRINT: 8, + ORUNESTR: 8, + OSIZEOF: 8, + OSTR2BYTES: 8, + OSTR2RUNES: 8, + OSTRUCTLIT: 8, + OTARRAY: 8, + OTCHAN: 8, + OTFUNC: 8, + OTINTER: 8, + OTMAP: 8, + OTSTRUCT: 8, + OINDEXMAP: 8, + OINDEX: 8, + OSLICE: 8, + OSLICESTR: 8, + OSLICEARR: 8, + OSLICE3: 8, + OSLICE3ARR: 8, + OSLICEHEADER: 8, + ODOTINTER: 8, + ODOTMETH: 8, + ODOTPTR: 8, + ODOTTYPE2: 8, + ODOTTYPE: 8, + ODOT: 8, + OXDOT: 8, + OCALLPART: 8, + OPLUS: 7, + ONOT: 7, + OBITNOT: 7, + ONEG: 7, + OADDR: 7, + ODEREF: 7, + ORECV: 7, + OMUL: 6, + ODIV: 6, + OMOD: 6, + OLSH: 6, + ORSH: 6, + OAND: 6, + OANDNOT: 6, + OADD: 5, + OSUB: 5, + OOR: 5, + OXOR: 5, + OEQ: 4, + OLT: 4, + OLE: 4, + OGE: 4, + OGT: 4, + ONE: 4, + OSEND: 3, + OANDAND: 2, + OOROR: 1, // Statements handled by stmtfmt OAS: -1, @@ -1172,7 +1172,7 @@ var opprec = []int{ OGOTO: -1, OIF: -1, OLABEL: -1, - OPROC: -1, + OGO: -1, ORANGE: -1, ORETURN: -1, OSELECT: -1, @@ -1183,7 +1183,7 @@ var opprec = []int{ } func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) { - for n != nil && n.Implicit() && (n.Op == OIND || n.Op == OADDR) { + for n != nil && n.Implicit() && (n.Op == ODEREF || n.Op == OADDR) { n = n.Left } @@ -1406,10 +1406,10 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) { case OCONV, OCONVIFACE, OCONVNOP, - OARRAYBYTESTR, - OARRAYRUNESTR, - OSTRARRAYBYTE, - OSTRARRAYRUNE, + OBYTES2STR, + ORUNES2STR, + OSTR2BYTES, + OSTR2RUNES, ORUNESTR: if n.Type == nil || n.Type.Sym == nil { mode.Fprintf(s, "(%v)", n.Type) @@ -1442,7 +1442,7 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) { mode.Fprintf(s, "%#v(%v)", n.Op, n.Left) return } - if n.Isddd() { + if n.IsDDD() { mode.Fprintf(s, "%#v(%.v...)", n.Op, n.List) return } @@ -1450,7 +1450,7 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) { case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG: n.Left.exprfmt(s, nprec, mode) - if n.Isddd() { + if n.IsDDD() { mode.Fprintf(s, "(%.v...)", n.List) return } @@ -1471,7 +1471,7 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) { } mode.Fprintf(s, "make(%v)", n.Type) - case OPLUS, OMINUS, OADDR, OCOM, OIND, ONOT, ORECV: + case OPLUS, ONEG, OADDR, OBITNOT, ODEREF, ONOT, ORECV: // Unary mode.Fprintf(s, "%#v", n.Op) if n.Left != nil && n.Left.Op == n.Op { @@ -1694,7 +1694,7 @@ func fldconv(f *types.Field, flag FmtFlag, mode fmtMode, depth int, funarg types } var typ string - if f.Isddd() { + if f.IsDDD() { var et *types.Type if f.Type != nil { et = f.Type.Elem() diff --git a/src/cmd/compile/internal/gc/iexport.go b/src/cmd/compile/internal/gc/iexport.go index e77ca9a6c1794b..cc43c2e2876d26 100644 --- a/src/cmd/compile/internal/gc/iexport.go +++ b/src/cmd/compile/internal/gc/iexport.go @@ -439,7 +439,7 @@ func (p *iexporter) doDecl(n *Node) { case OLITERAL: // Constant. - n = typecheck(n, Erv) + n = typecheck(n, ctxExpr) w.tag('C') w.pos(n.Pos) w.value(n.Type, n.Val()) @@ -707,7 +707,7 @@ func (w *exportWriter) signature(t *types.Type) { w.paramList(t.Params().FieldSlice()) w.paramList(t.Results().FieldSlice()) if n := t.Params().NumFields(); n > 0 { - w.bool(t.Params().Field(n - 1).Isddd()) + w.bool(t.Params().Field(n - 1).IsDDD()) } } @@ -1047,7 +1047,7 @@ func (w *exportWriter) stmt(n *Node) { // case ORETJMP: // unreachable - generated by compiler for trampolin routines - case OPROC, ODEFER: + case OGO, ODEFER: w.op(op) w.pos(n.Pos) w.expr(n.Left) @@ -1127,7 +1127,7 @@ func (w *exportWriter) expr(n *Node) { // } // from exprfmt (fmt.go) - for n.Op == OPAREN || n.Implicit() && (n.Op == OIND || n.Op == OADDR || n.Op == ODOT || n.Op == ODOTPTR) { + for n.Op == OPAREN || n.Implicit() && (n.Op == ODEREF || n.Op == OADDR || n.Op == ODOT || n.Op == ODOTPTR) { n = n.Left } @@ -1252,7 +1252,7 @@ func (w *exportWriter) expr(n *Node) { w.expr(n.Right) w.op(OEND) - case OCONV, OCONVIFACE, OCONVNOP, OARRAYBYTESTR, OARRAYRUNESTR, OSTRARRAYBYTE, OSTRARRAYRUNE, ORUNESTR: + case OCONV, OCONVIFACE, OCONVNOP, OBYTES2STR, ORUNES2STR, OSTR2BYTES, OSTR2RUNES, ORUNESTR: w.op(OCONV) w.pos(n.Pos) w.expr(n.Left) @@ -1269,8 +1269,8 @@ func (w *exportWriter) expr(n *Node) { } // only append() calls may contain '...' arguments if op == OAPPEND { - w.bool(n.Isddd()) - } else if n.Isddd() { + w.bool(n.IsDDD()) + } else if n.IsDDD() { Fatalf("exporter: unexpected '...' with %v call", op) } @@ -1279,7 +1279,7 @@ func (w *exportWriter) expr(n *Node) { w.pos(n.Pos) w.expr(n.Left) w.exprList(n.List) - w.bool(n.Isddd()) + w.bool(n.IsDDD()) case OMAKEMAP, OMAKECHAN, OMAKESLICE: w.op(op) // must keep separate from OMAKE for importer @@ -1301,7 +1301,7 @@ func (w *exportWriter) expr(n *Node) { } // unary expressions - case OPLUS, OMINUS, OADDR, OCOM, OIND, ONOT, ORECV: + case OPLUS, ONEG, OADDR, OBITNOT, ODEREF, ONOT, ORECV: w.op(op) w.pos(n.Pos) w.expr(n.Left) diff --git a/src/cmd/compile/internal/gc/iimport.go b/src/cmd/compile/internal/gc/iimport.go index c9198499dd6430..ff98b79835f27d 100644 --- a/src/cmd/compile/internal/gc/iimport.go +++ b/src/cmd/compile/internal/gc/iimport.go @@ -608,7 +608,7 @@ func (r *importReader) signature(recv *types.Field) *types.Type { params := r.paramList() results := r.paramList() if n := len(params); n > 0 { - params[n-1].SetIsddd(r.bool()) + params[n-1].SetIsDDD(r.bool()) } t := functypefield(recv, params, results) t.SetPkg(r.currPkg) @@ -820,7 +820,7 @@ func (r *importReader) node() *Node { if !r.bool() /* !implicit, i.e. '&' operator */ { if n.Op == OCOMPLIT { // Special case for &T{...}: turn into (*T){...}. - n.Right = nodl(pos, OIND, n.Right, nil) + n.Right = nodl(pos, ODEREF, n.Right, nil) n.Right.SetImplicit(true) } else { n = nodl(pos, OADDR, n, nil) @@ -887,7 +887,7 @@ func (r *importReader) node() *Node { n.SetSliceBounds(low, high, max) return n - // case OCONV, OCONVIFACE, OCONVNOP, OARRAYBYTESTR, OARRAYRUNESTR, OSTRARRAYBYTE, OSTRARRAYRUNE, ORUNESTR: + // case OCONV, OCONVIFACE, OCONVNOP, OBYTES2STR, ORUNES2STR, OSTR2BYTES, OSTR2RUNES, ORUNESTR: // unreachable - mapped to OCONV case below by exporter case OCONV: @@ -899,7 +899,7 @@ func (r *importReader) node() *Node { n := npos(r.pos(), builtinCall(op)) n.List.Set(r.exprList()) if op == OAPPEND { - n.SetIsddd(r.bool()) + n.SetIsDDD(r.bool()) } return n @@ -909,7 +909,7 @@ func (r *importReader) node() *Node { case OCALL: n := nodl(r.pos(), OCALL, r.expr(), nil) n.List.Set(r.exprList()) - n.SetIsddd(r.bool()) + n.SetIsDDD(r.bool()) return n case OMAKEMAP, OMAKECHAN, OMAKESLICE: @@ -919,7 +919,7 @@ func (r *importReader) node() *Node { return n // unary expressions - case OPLUS, OMINUS, OADDR, OCOM, OIND, ONOT, ORECV: + case OPLUS, ONEG, OADDR, OBITNOT, ODEREF, ONOT, ORECV: return nodl(r.pos(), op, r.expr(), nil) // binary expressions @@ -982,7 +982,7 @@ func (r *importReader) node() *Node { // case ORETJMP: // unreachable - generated by compiler for trampolin routines (not exported) - case OPROC, ODEFER: + case OGO, ODEFER: return nodl(r.pos(), op, r.expr(), nil) case OIF: diff --git a/src/cmd/compile/internal/gc/init.go b/src/cmd/compile/internal/gc/init.go index bb2bc4b844e65e..ae8748807547fa 100644 --- a/src/cmd/compile/internal/gc/init.go +++ b/src/cmd/compile/internal/gc/init.go @@ -166,7 +166,7 @@ func fninit(n []*Node) { rhs := asNode(s.Def) rhs.checkInitFuncSignature() as := nod(OAS, lhs, rhs) - as = typecheck(as, Etop) + as = typecheck(as, ctxStmt) genAsStatic(as) } @@ -187,7 +187,7 @@ func fninit(n []*Node) { loop.Nbody.Set1(body) loop.Ninit.Set1(zero) - loop = typecheck(loop, Etop) + loop = typecheck(loop, ctxStmt) r = append(r, loop) } @@ -206,8 +206,8 @@ func fninit(n []*Node) { funcbody() Curfn = fn - fn = typecheck(fn, Etop) - typecheckslice(r, Etop) + fn = typecheck(fn, ctxStmt) + typecheckslice(r, ctxStmt) Curfn = nil funccompile(fn) } diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go index b26758a77ead89..3f649be7cb0b2f 100644 --- a/src/cmd/compile/internal/gc/inl.go +++ b/src/cmd/compile/internal/gc/inl.go @@ -90,7 +90,7 @@ func typecheckinl(fn *Node) { savefn := Curfn Curfn = fn - typecheckslice(fn.Func.Inl.Body, Etop) + typecheckslice(fn.Func.Inl.Body, ctxStmt) Curfn = savefn // During typechecking, declarations are added to @@ -377,7 +377,7 @@ func (v *hairyVisitor) visit(n *Node) bool { OFORUNTIL, OSELECT, OTYPESW, - OPROC, + OGO, ODEFER, ODCLTYPE, // can't print yet OBREAK, @@ -552,7 +552,7 @@ func inlnode(n *Node, maxCost int32) *Node { switch n.Op { // inhibit inlining of their argument - case ODEFER, OPROC: + case ODEFER, OGO: switch n.Left.Op { case OCALLFUNC, OCALLMETH: n.Left.SetNoInline(true) @@ -620,7 +620,7 @@ func inlnode(n *Node, maxCost int32) *Node { n.Rlist.Set(inlconv2list(n.Rlist.First())) n.Op = OAS2 n.SetTypecheck(0) - n = typecheck(n, Etop) + n = typecheck(n, ctxStmt) } else { s := n.Rlist.Slice() for i1, n1 := range s { @@ -815,7 +815,7 @@ func tinlvar(t *types.Field, inlvars map[*Node]*Node) *Node { return inlvar } - return typecheck(nblank, Erv|Easgn) + return typecheck(nblank, ctxExpr|ctxAssign) } var inlgen int @@ -897,21 +897,21 @@ func mkinlcall(n, fn *Node, maxCost int32) *Node { } if v.Name.Byval() { - iv := typecheck(inlvar(v), Erv) + iv := typecheck(inlvar(v), ctxExpr) ninit.Append(nod(ODCL, iv, nil)) - ninit.Append(typecheck(nod(OAS, iv, o), Etop)) + ninit.Append(typecheck(nod(OAS, iv, o), ctxStmt)) inlvars[v] = iv } else { addr := newname(lookup("&" + v.Sym.Name)) addr.Type = types.NewPtr(v.Type) - ia := typecheck(inlvar(addr), Erv) + ia := typecheck(inlvar(addr), ctxExpr) ninit.Append(nod(ODCL, ia, nil)) - ninit.Append(typecheck(nod(OAS, ia, nod(OADDR, o, nil)), Etop)) + ninit.Append(typecheck(nod(OAS, ia, nod(OADDR, o, nil)), ctxStmt)) inlvars[addr] = ia // When capturing by reference, all occurrence of the captured var // must be substituted with dereference of the temporary address - inlvars[v] = typecheck(nod(OIND, ia, nil), Erv) + inlvars[v] = typecheck(nod(ODEREF, ia, nil), ctxExpr) } } } @@ -927,7 +927,7 @@ func mkinlcall(n, fn *Node, maxCost int32) *Node { if ln.isParamStackCopy() { // ignore the on-stack copy of a parameter that moved to the heap continue } - inlvars[ln] = typecheck(inlvar(ln), Erv) + inlvars[ln] = typecheck(inlvar(ln), ctxExpr) if ln.Class() == PPARAM || ln.Name.Param.Stackcopy != nil && ln.Name.Param.Stackcopy.Class() == PPARAM { ninit.Append(nod(ODCL, inlvars[ln], nil)) } @@ -950,7 +950,7 @@ func mkinlcall(n, fn *Node, maxCost int32) *Node { mpos := t.Pos if n := asNode(t.Nname); n != nil && !n.isBlank() { m = inlvar(n) - m = typecheck(m, Erv) + m = typecheck(m, ctxExpr) inlvars[n] = m } else { // anonymous return values, synthesize names for use in assignment that replaces return @@ -990,7 +990,7 @@ func mkinlcall(n, fn *Node, maxCost int32) *Node { Fatalf("method call without receiver: %+v", n) } ras := nod(OAS, tinlvar(rcv, inlvars), n.Left.Left) - ras = typecheck(ras, Etop) + ras = typecheck(ras, ctxStmt) ninit.Append(ras) } else { // For T.M(...), add the receiver parameter to @@ -1007,7 +1007,7 @@ func mkinlcall(n, fn *Node, maxCost int32) *Node { // For ordinary parameters or variadic parameters in // dotted calls, just add the variable to the // assignment list, and we're done. - if !param.Isddd() || n.Isddd() { + if !param.IsDDD() || n.IsDDD() { as.List.Append(tinlvar(param, inlvars)) continue } @@ -1037,19 +1037,19 @@ func mkinlcall(n, fn *Node, maxCost int32) *Node { } if as.Rlist.Len() != 0 { - as = typecheck(as, Etop) + as = typecheck(as, ctxStmt) ninit.Append(as) } if vas != nil { - vas = typecheck(vas, Etop) + vas = typecheck(vas, ctxStmt) ninit.Append(vas) } // Zero the return parameters. for _, n := range retvars { ras := nod(OAS, n, nil) - ras = typecheck(ras, Etop) + ras = typecheck(ras, ctxStmt) ninit.Append(ras) } @@ -1083,7 +1083,7 @@ func mkinlcall(n, fn *Node, maxCost int32) *Node { lab := nodSym(OLABEL, nil, retlabel) body = append(body, lab) - typecheckslice(body, Etop) + typecheckslice(body, ctxStmt) if genDwarfInline > 0 { for _, v := range inlfvars { @@ -1239,12 +1239,12 @@ func (subst *inlsubst) node(n *Node) *Node { as.List.Append(n) } as.Rlist.Set(subst.list(n.List)) - as = typecheck(as, Etop) + as = typecheck(as, ctxStmt) m.Ninit.Append(as) } - typecheckslice(m.Ninit.Slice(), Etop) - m = typecheck(m, Etop) + typecheckslice(m.Ninit.Slice(), ctxStmt) + m = typecheck(m, ctxStmt) // dump("Return after substitution", m); return m diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index 7e9dd4d5cd3440..b843ebf4370476 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -509,7 +509,7 @@ func Main(archInit func(*Arch)) { for i := 0; i < len(xtop); i++ { n := xtop[i] if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias) { - xtop[i] = typecheck(n, Etop) + xtop[i] = typecheck(n, ctxStmt) } } @@ -521,7 +521,7 @@ func Main(archInit func(*Arch)) { for i := 0; i < len(xtop); i++ { n := xtop[i] if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias { - xtop[i] = typecheck(n, Etop) + xtop[i] = typecheck(n, ctxStmt) } } resumecheckwidth() @@ -536,7 +536,7 @@ func Main(archInit func(*Arch)) { Curfn = n decldepth = 1 saveerrors() - typecheckslice(Curfn.Nbody.Slice(), Etop) + typecheckslice(Curfn.Nbody.Slice(), ctxStmt) checkreturn(Curfn) if nerrors != 0 { Curfn.Nbody.Set(nil) // type errors; do not compile @@ -693,7 +693,7 @@ func Main(archInit func(*Arch)) { timings.Start("be", "externaldcls") for i, n := range externdcl { if n.Op == ONAME { - externdcl[i] = typecheck(externdcl[i], Erv) + externdcl[i] = typecheck(externdcl[i], ctxExpr) } } // Check the map keys again, since we typechecked the external diff --git a/src/cmd/compile/internal/gc/noder.go b/src/cmd/compile/internal/gc/noder.go index a2ed103c80c7aa..b9849e7a8491b8 100644 --- a/src/cmd/compile/internal/gc/noder.go +++ b/src/cmd/compile/internal/gc/noder.go @@ -542,9 +542,9 @@ func (p *noder) param(param *syntax.Field, dddOk, final bool) *Node { typ.Op = OTARRAY typ.Right = typ.Left typ.Left = nil - n.SetIsddd(true) + n.SetIsDDD(true) if n.Left != nil { - n.Left.SetIsddd(true) + n.Left.SetIsDDD(true) } } @@ -632,7 +632,7 @@ func (p *noder) expr(expr syntax.Expr) *Node { x = unparen(x) // TODO(mdempsky): Needed? if x.Op == OCOMPLIT { // Special case for &T{...}: turn into (*T){...}. - x.Right = p.nod(expr, OIND, x.Right, nil) + x.Right = p.nod(expr, ODEREF, x.Right, nil) x.Right.SetImplicit(true) return x } @@ -643,7 +643,7 @@ func (p *noder) expr(expr syntax.Expr) *Node { case *syntax.CallExpr: n := p.nod(expr, OCALL, p.expr(expr.Fun), nil) n.List.Set(p.exprs(expr.ArgList)) - n.SetIsddd(expr.HasDots) + n.SetIsDDD(expr.HasDots) return n case *syntax.ArrayType: @@ -870,7 +870,7 @@ func (p *noder) embedded(typ syntax.Expr) *Node { n.SetEmbedded(true) if isStar { - n.Left = p.nod(op, OIND, n.Left, nil) + n.Left = p.nod(op, ODEREF, n.Left, nil) } return n } @@ -969,7 +969,7 @@ func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) *Node { case syntax.Defer: op = ODEFER case syntax.Go: - op = OPROC + op = OGO default: panic("unhandled CallStmt") } @@ -1245,13 +1245,13 @@ func (p *noder) labeledStmt(label *syntax.LabeledStmt, fallOK bool) *Node { var unOps = [...]Op{ syntax.Recv: ORECV, - syntax.Mul: OIND, + syntax.Mul: ODEREF, syntax.And: OADDR, syntax.Not: ONOT, - syntax.Xor: OCOM, + syntax.Xor: OBITNOT, syntax.Add: OPLUS, - syntax.Sub: OMINUS, + syntax.Sub: ONEG, } func (p *noder) unOp(op syntax.Operator) Op { diff --git a/src/cmd/compile/internal/gc/op_string.go b/src/cmd/compile/internal/gc/op_string.go index 34c3249d903825..fe80e39064d781 100644 --- a/src/cmd/compile/internal/gc/op_string.go +++ b/src/cmd/compile/internal/gc/op_string.go @@ -4,9 +4,9 @@ package gc import "strconv" -const _Op_name = "XXXNAMENONAMETYPEPACKLITERALADDSUBORXORADDSTRADDRANDANDAPPENDARRAYBYTESTRARRAYBYTESTRTMPARRAYRUNESTRSTRARRAYBYTESTRARRAYBYTETMPSTRARRAYRUNEASAS2AS2FUNCAS2RECVAS2MAPRAS2DOTTYPEASOPCALLCALLFUNCCALLMETHCALLINTERCALLPARTCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLFIELDDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTINDINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMULDIVMODLSHRSHANDANDNOTNEWNOTCOMPLUSMINUSORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECVRUNESTRSELRECVSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFBLOCKBREAKCASEXCASECONTINUEDEFEREMPTYFALLFORFORUNTILGOTOIFLABELPROCRANGERETURNSELECTSWITCHTYPESWTCHANTMAPTSTRUCTTINTERTFUNCTARRAYDDDDDDARGINLCALLEFACEITABIDATASPTRCLOSUREVARCFUNCCHECKNILVARDEFVARKILLVARLIVEINDREGSPRETJMPGETGEND" +const _Op_name = "XXXNAMENONAMETYPEPACKLITERALADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESASAS2AS2FUNCAS2RECVAS2MAPRAS2DOTTYPEASOPCALLCALLFUNCCALLMETHCALLINTERCALLPARTCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLFIELDDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECVRUNESTRSELRECVSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFBLOCKBREAKCASEXCASECONTINUEDEFEREMPTYFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWTCHANTMAPTSTRUCTTINTERTFUNCTARRAYDDDDDDARGINLCALLEFACEITABIDATASPTRCLOSUREVARCFUNCCHECKNILVARDEFVARKILLVARLIVEINDREGSPRETJMPGETGEND" -var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 36, 39, 45, 49, 55, 61, 73, 88, 100, 112, 127, 139, 141, 144, 151, 158, 165, 175, 179, 183, 191, 199, 208, 216, 219, 224, 231, 238, 244, 253, 261, 269, 275, 279, 288, 295, 299, 302, 309, 317, 325, 332, 338, 341, 347, 354, 362, 366, 373, 381, 383, 385, 387, 389, 391, 393, 396, 401, 409, 412, 421, 424, 428, 436, 443, 452, 455, 458, 461, 464, 467, 470, 476, 479, 482, 485, 489, 494, 498, 503, 508, 514, 519, 523, 528, 536, 544, 550, 559, 570, 577, 581, 588, 595, 603, 607, 611, 615, 622, 629, 637, 643, 648, 653, 657, 662, 670, 675, 680, 684, 687, 695, 699, 701, 706, 710, 715, 721, 727, 733, 739, 744, 748, 755, 761, 766, 772, 775, 781, 788, 793, 797, 802, 806, 816, 821, 829, 835, 842, 849, 857, 863, 867, 870} +var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 36, 39, 45, 49, 55, 61, 70, 82, 91, 100, 112, 121, 123, 126, 133, 140, 147, 157, 161, 165, 173, 181, 190, 198, 201, 206, 213, 220, 226, 235, 243, 251, 257, 261, 270, 277, 281, 284, 291, 299, 307, 314, 320, 323, 329, 336, 344, 348, 355, 363, 365, 367, 369, 371, 373, 375, 380, 385, 393, 396, 405, 408, 412, 420, 427, 436, 439, 442, 445, 448, 451, 454, 460, 463, 466, 472, 476, 479, 483, 488, 493, 499, 504, 508, 513, 521, 529, 535, 544, 555, 562, 566, 573, 580, 588, 592, 596, 600, 607, 614, 622, 628, 633, 638, 642, 647, 655, 660, 665, 669, 672, 680, 684, 686, 691, 693, 698, 704, 710, 716, 722, 727, 731, 738, 744, 749, 755, 758, 764, 771, 776, 780, 785, 789, 799, 804, 812, 818, 825, 832, 840, 846, 850, 853} func (i Op) String() string { if i >= Op(len(_Op_index)-1) { diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go index da2b3343a131f5..2eec537e4e6cbf 100644 --- a/src/cmd/compile/internal/gc/order.go +++ b/src/cmd/compile/internal/gc/order.go @@ -81,7 +81,7 @@ func (o *Order) newTemp(t *types.Type, clear bool) *Node { } if clear { a := nod(OAS, v, nil) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) o.out = append(o.out, a) } @@ -104,7 +104,7 @@ func (o *Order) newTemp(t *types.Type, clear bool) *Node { func (o *Order) copyExpr(n *Node, t *types.Type, clear bool) *Node { v := o.newTemp(t, clear) a := nod(OAS, v, n) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) o.out = append(o.out, a) return v } @@ -128,7 +128,7 @@ func (o *Order) cheapExpr(n *Node) *Node { } a := n.sepcopy() a.Left = l - return typecheck(a, Erv) + return typecheck(a, ctxExpr) } return o.copyExpr(n, n.Type, false) @@ -153,16 +153,16 @@ func (o *Order) safeExpr(n *Node) *Node { } a := n.sepcopy() a.Left = l - return typecheck(a, Erv) + return typecheck(a, ctxExpr) - case ODOTPTR, OIND: + case ODOTPTR, ODEREF: l := o.cheapExpr(n.Left) if l == n.Left { return n } a := n.sepcopy() a.Left = l - return typecheck(a, Erv) + return typecheck(a, ctxExpr) case OINDEX, OINDEXMAP: var l *Node @@ -178,7 +178,7 @@ func (o *Order) safeExpr(n *Node) *Node { a := n.sepcopy() a.Left = l a.Right = r - return typecheck(a, Erv) + return typecheck(a, ctxExpr) default: Fatalf("ordersafeexpr %v", n.Op) @@ -213,7 +213,7 @@ func (o *Order) addrTemp(n *Node) *Node { if out != nil { Fatalf("staticassign of const generated code: %+v", n) } - vstat = typecheck(vstat, Erv) + vstat = typecheck(vstat, ctxExpr) return vstat } if isaddrokay(n) { @@ -233,7 +233,7 @@ func (o *Order) mapKeyTemp(t *types.Type, n *Node) *Node { return n } -// mapKeyReplaceStrConv replaces OARRAYBYTESTR by OARRAYBYTESTRTMP +// mapKeyReplaceStrConv replaces OBYTES2STR by OBYTES2STRTMP // in n to avoid string allocations for keys in map lookups. // Returns a bool that signals if a modification was made. // @@ -250,8 +250,8 @@ func (o *Order) mapKeyTemp(t *types.Type, n *Node) *Node { func mapKeyReplaceStrConv(n *Node) bool { var replaced bool switch n.Op { - case OARRAYBYTESTR: - n.Op = OARRAYBYTESTRTMP + case OBYTES2STR: + n.Op = OBYTES2STRTMP replaced = true case OSTRUCTLIT: for _, elem := range n.List.Slice() { @@ -300,11 +300,11 @@ func (o *Order) cleanTempNoPop(mark ordermarker) []*Node { n.Name.SetKeepalive(false) n.SetAddrtaken(true) // ensure SSA keeps the n variable live := nod(OVARLIVE, n, nil) - live = typecheck(live, Etop) + live = typecheck(live, ctxStmt) out = append(out, live) } kill := nod(OVARKILL, n, nil) - kill = typecheck(kill, Etop) + kill = typecheck(kill, ctxStmt) out = append(out, kill) } return out @@ -418,7 +418,7 @@ func (o *Order) copyRet(n *Node) []*Node { as := nod(OAS2, nil, nil) as.List.Set(l1) as.Rlist.Set1(n) - as = typecheck(as, Etop) + as = typecheck(as, ctxStmt) o.stmt(as) return l2 @@ -463,7 +463,7 @@ func (o *Order) call(n *Node) { for i, t := range n.Left.Type.Params().FieldSlice() { // Check for "unsafe-uintptr" tag provided by escape analysis. - if t.Isddd() && !n.Isddd() { + if t.IsDDD() && !n.IsDDD() { if t.Note == uintptrEscapesTag { for ; i < n.List.Len(); i++ { keepAlive(i) @@ -528,7 +528,7 @@ func (o *Order) mapAssign(n *Node) { t := o.newTemp(m.Type, false) n.List.SetIndex(i, t) a := nod(OAS, m, t) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) post = append(post, a) } } @@ -602,7 +602,7 @@ func (o *Order) stmt(n *Node) { } l = o.copyExpr(l, n.Left.Type, false) n.Right = nod(n.SubOp(), l, n.Right) - n.Right = typecheck(n.Right, Erv) + n.Right = typecheck(n.Right, ctxExpr) n.Right = o.expr(n.Right, nil) n.Op = OAS @@ -657,10 +657,10 @@ func (o *Order) stmt(n *Node) { tmp2 := o.newTemp(types.Types[TBOOL], false) o.out = append(o.out, n) r := nod(OAS, n.List.First(), tmp1) - r = typecheck(r, Etop) + r = typecheck(r, ctxStmt) o.mapAssign(r) r = okas(n.List.Second(), tmp2) - r = typecheck(r, Etop) + r = typecheck(r, ctxStmt) o.mapAssign(r) n.List.Set2(tmp1, tmp2) o.cleanTemp(t) @@ -689,7 +689,7 @@ func (o *Order) stmt(n *Node) { o.cleanTemp(t) // Special: order arguments to inner call but not call itself. - case ODEFER, OPROC: + case ODEFER, OGO: t := o.markTemp() o.call(n.Left) o.out = append(o.out, n) @@ -751,8 +751,8 @@ func (o *Order) stmt(n *Node) { // Mark []byte(str) range expression to reuse string backing storage. // It is safe because the storage cannot be mutated. - if n.Right.Op == OSTRARRAYBYTE { - n.Right.Op = OSTRARRAYBYTETMP + if n.Right.Op == OSTR2BYTES { + n.Right.Op = OSTR2BYTESTMP } t := o.markTemp() @@ -779,7 +779,7 @@ func (o *Order) stmt(n *Node) { if r.Type.IsString() && r.Type != types.Types[TSTRING] { r = nod(OCONV, r, nil) r.Type = types.Types[TSTRING] - r = typecheck(r, Erv) + r = typecheck(r, ctxExpr) } n.Right = o.copyExpr(r, r.Type, false) @@ -897,13 +897,13 @@ func (o *Order) stmt(n *Node) { if r.Colas() { tmp2 := nod(ODCL, tmp1, nil) - tmp2 = typecheck(tmp2, Etop) + tmp2 = typecheck(tmp2, ctxStmt) n2.Ninit.Append(tmp2) } r.Left = o.newTemp(r.Right.Left.Type.Elem(), types.Haspointers(r.Right.Left.Type.Elem())) tmp2 := nod(OAS, tmp1, r.Left) - tmp2 = typecheck(tmp2, Etop) + tmp2 = typecheck(tmp2, ctxStmt) n2.Ninit.Append(tmp2) } @@ -914,13 +914,13 @@ func (o *Order) stmt(n *Node) { tmp1 := r.List.First() if r.Colas() { tmp2 := nod(ODCL, tmp1, nil) - tmp2 = typecheck(tmp2, Etop) + tmp2 = typecheck(tmp2, ctxStmt) n2.Ninit.Append(tmp2) } r.List.Set1(o.newTemp(types.Types[TBOOL], false)) tmp2 := okas(tmp1, r.List.First()) - tmp2 = typecheck(tmp2, Etop) + tmp2 = typecheck(tmp2, ctxStmt) n2.Ninit.Append(tmp2) } orderBlock(&n2.Ninit, o.free) @@ -1064,14 +1064,14 @@ func (o *Order) expr(n, lhs *Node) *Node { haslit := false for _, n1 := range n.List.Slice() { - hasbyte = hasbyte || n1.Op == OARRAYBYTESTR + hasbyte = hasbyte || n1.Op == OBYTES2STR haslit = haslit || n1.Op == OLITERAL && len(n1.Val().U.(string)) != 0 } if haslit && hasbyte { for _, n2 := range n.List.Slice() { - if n2.Op == OARRAYBYTESTR { - n2.Op = OARRAYBYTESTRTMP + if n2.Op == OBYTES2STR { + n2.Op = OBYTES2STRTMP } } } @@ -1153,9 +1153,9 @@ func (o *Order) expr(n, lhs *Node) *Node { ONEW, OREAL, ORECOVER, - OSTRARRAYBYTE, - OSTRARRAYBYTETMP, - OSTRARRAYRUNE: + OSTR2BYTES, + OSTR2BYTESTMP, + OSTR2RUNES: if isRuneCount(n) { // len([]rune(s)) is rewritten to runtime.countrunes(s) later. @@ -1248,11 +1248,11 @@ func (o *Order) expr(n, lhs *Node) *Node { // Mark string(byteSlice) arguments to reuse byteSlice backing // buffer during conversion. String comparison does not // memorize the strings for later use, so it is safe. - if n.Left.Op == OARRAYBYTESTR { - n.Left.Op = OARRAYBYTESTRTMP + if n.Left.Op == OBYTES2STR { + n.Left.Op = OBYTES2STRTMP } - if n.Right.Op == OARRAYBYTESTR { - n.Right.Op = OARRAYBYTESTRTMP + if n.Right.Op == OBYTES2STR { + n.Right.Op = OBYTES2STRTMP } case t.IsStruct() || t.IsArray(): @@ -1301,7 +1301,7 @@ func (o *Order) as2(n *Node) { as := nod(OAS2, nil, nil) as.List.Set(left) as.Rlist.Set(tmplist) - as = typecheck(as, Etop) + as = typecheck(as, ctxStmt) o.stmt(as) } @@ -1322,13 +1322,13 @@ func (o *Order) okAs2(n *Node) { if tmp1 != nil { r := nod(OAS, n.List.First(), tmp1) - r = typecheck(r, Etop) + r = typecheck(r, ctxStmt) o.mapAssign(r) n.List.SetFirst(tmp1) } if tmp2 != nil { r := okas(n.List.Second(), tmp2) - r = typecheck(r, Etop) + r = typecheck(r, ctxStmt) o.mapAssign(r) n.List.SetSecond(tmp2) } diff --git a/src/cmd/compile/internal/gc/range.go b/src/cmd/compile/internal/gc/range.go index ac03cc5ea7dac2..bf30d9388ec55f 100644 --- a/src/cmd/compile/internal/gc/range.go +++ b/src/cmd/compile/internal/gc/range.go @@ -28,17 +28,17 @@ func typecheckrange(n *Node) { ls := n.List.Slice() for i1, n1 := range ls { if n1.Typecheck() == 0 { - ls[i1] = typecheck(ls[i1], Erv|Easgn) + ls[i1] = typecheck(ls[i1], ctxExpr|ctxAssign) } } decldepth++ - typecheckslice(n.Nbody.Slice(), Etop) + typecheckslice(n.Nbody.Slice(), ctxStmt) decldepth-- } func typecheckrangeExpr(n *Node) { - n.Right = typecheck(n.Right, Erv) + n.Right = typecheck(n.Right, ctxExpr) t := n.Right.Type if t == nil { @@ -48,7 +48,7 @@ func typecheckrangeExpr(n *Node) { ls := n.List.Slice() for i1, n1 := range ls { if n1.Name == nil || n1.Name.Defn != n { - ls[i1] = typecheck(ls[i1], Erv|Easgn) + ls[i1] = typecheck(ls[i1], ctxExpr|ctxAssign) } } @@ -278,7 +278,7 @@ func walkrange(n *Node) *Node { // of the form "v1, a[v1] := range". a := nod(OAS2, nil, nil) a.List.Set2(v1, v2) - a.Rlist.Set2(hv1, nod(OIND, hp, nil)) + a.Rlist.Set2(hv1, nod(ODEREF, hp, nil)) body = append(body, a) // Advance pointer as part of the late increment. @@ -287,7 +287,7 @@ func walkrange(n *Node) *Node { // advancing the pointer is safe and won't go past the // end of the allocation. a = nod(OAS, hp, addptr(hp, t.Elem().Width)) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) n.List.Set1(a) case TMAP: @@ -312,14 +312,14 @@ func walkrange(n *Node) *Node { n.Right = mkcall1(fn, nil, nil, nod(OADDR, hit, nil)) key := nodSym(ODOT, hit, keysym) - key = nod(OIND, key, nil) + key = nod(ODEREF, key, nil) if v1 == nil { body = nil } else if v2 == nil { body = []*Node{nod(OAS, v1, key)} } else { val := nodSym(ODOT, hit, valsym) - val = nod(OIND, val, nil) + val = nod(ODEREF, val, nil) a := nod(OAS2, nil, nil) a.List.Set2(v1, v2) a.Rlist.Set2(key, val) @@ -427,21 +427,21 @@ func walkrange(n *Node) *Node { } n.Op = translatedLoopOp - typecheckslice(init, Etop) + typecheckslice(init, ctxStmt) if ifGuard != nil { ifGuard.Ninit.Append(init...) - ifGuard = typecheck(ifGuard, Etop) + ifGuard = typecheck(ifGuard, ctxStmt) } else { n.Ninit.Append(init...) } - typecheckslice(n.Left.Ninit.Slice(), Etop) + typecheckslice(n.Left.Ninit.Slice(), ctxStmt) - n.Left = typecheck(n.Left, Erv) + n.Left = typecheck(n.Left, ctxExpr) n.Left = defaultlit(n.Left, nil) - n.Right = typecheck(n.Right, Etop) - typecheckslice(body, Etop) + n.Right = typecheck(n.Right, ctxStmt) + typecheckslice(body, ctxStmt) n.Nbody.Prepend(body...) if ifGuard != nil { @@ -512,7 +512,7 @@ func mapClear(m *Node) *Node { fn = substArgTypes(fn, t.Key(), t.Elem()) n := mkcall1(fn, nil, nil, typename(t), m) - n = typecheck(n, Etop) + n = typecheck(n, ctxStmt) n = walkstmt(n) return n @@ -601,9 +601,9 @@ func arrayClear(n, v1, v2, a *Node) bool { n.Nbody.Append(v1) - n.Left = typecheck(n.Left, Erv) + n.Left = typecheck(n.Left, ctxExpr) n.Left = defaultlit(n.Left, nil) - typecheckslice(n.Nbody.Slice(), Etop) + typecheckslice(n.Nbody.Slice(), ctxStmt) n = walkstmt(n) return true } diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go index 130c83036c970f..8310b8d2fc8c7f 100644 --- a/src/cmd/compile/internal/gc/reflect.go +++ b/src/cmd/compile/internal/gc/reflect.go @@ -333,7 +333,7 @@ func methodfunc(f *types.Type, receiver *types.Type) *types.Type { for _, t := range f.Params().Fields().Slice() { d := anonfield(t.Type) - d.SetIsddd(t.Isddd()) + d.SetIsDDD(t.IsDDD()) in = append(in, d) } @@ -1180,7 +1180,7 @@ func dtypesym(t *types.Type) *obj.LSym { } isddd := false for _, t1 := range t.Params().Fields().Slice() { - isddd = t1.Isddd() + isddd = t1.IsDDD() dtypesym(t1.Type) } for _, t1 := range t.Results().Fields().Slice() { diff --git a/src/cmd/compile/internal/gc/select.go b/src/cmd/compile/internal/gc/select.go index c7f39088880f90..a09d779af67821 100644 --- a/src/cmd/compile/internal/gc/select.go +++ b/src/cmd/compile/internal/gc/select.go @@ -10,7 +10,7 @@ import "cmd/compile/internal/types" func typecheckselect(sel *Node) { var def *Node lno := setlineno(sel) - typecheckslice(sel.Ninit.Slice(), Etop) + typecheckslice(sel.Ninit.Slice(), ctxStmt) for _, ncase := range sel.List.Slice() { if ncase.Op != OXCASE { setlineno(ncase) @@ -27,7 +27,7 @@ func typecheckselect(sel *Node) { } else if ncase.List.Len() > 1 { yyerrorl(ncase.Pos, "select cases cannot be lists") } else { - ncase.List.SetFirst(typecheck(ncase.List.First(), Etop)) + ncase.List.SetFirst(typecheck(ncase.List.First(), ctxStmt)) n := ncase.List.First() ncase.Left = n ncase.List.Set(nil) @@ -83,7 +83,7 @@ func typecheckselect(sel *Node) { } } - typecheckslice(ncase.Nbody.Slice(), Etop) + typecheckslice(ncase.Nbody.Slice(), ctxStmt) } lineno = lno @@ -148,7 +148,7 @@ func walkselectcases(cases *Nodes) []*Node { } if n.Left == nil { - nblank = typecheck(nblank, Erv|Easgn) + nblank = typecheck(nblank, ctxExpr|ctxAssign) n.Left = nblank } @@ -158,7 +158,7 @@ func walkselectcases(cases *Nodes) []*Node { n.Right = nil n.Left = nil n.SetTypecheck(0) - n = typecheck(n, Etop) + n = typecheck(n, ctxStmt) } // if ch == nil { block() }; n; @@ -169,7 +169,7 @@ func walkselectcases(cases *Nodes) []*Node { ln.Set(l) a.Nbody.Set1(mkcall("block", nil, &ln)) l = ln.Slice() - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) l = append(l, a, n) } @@ -189,7 +189,7 @@ func walkselectcases(cases *Nodes) []*Node { switch n.Op { case OSEND: n.Right = nod(OADDR, n.Right, nil) - n.Right = typecheck(n.Right, Erv) + n.Right = typecheck(n.Right, ctxExpr) case OSELRECV, OSELRECV2: if n.Op == OSELRECV2 && n.List.Len() == 0 { @@ -198,7 +198,7 @@ func walkselectcases(cases *Nodes) []*Node { if n.Left != nil { n.Left = nod(OADDR, n.Left, nil) - n.Left = typecheck(n.Left, Erv) + n.Left = typecheck(n.Left, ctxExpr) } } } @@ -249,11 +249,11 @@ func walkselectcases(cases *Nodes) []*Node { elem = nodnil() } receivedp := nod(OADDR, n.List.First(), nil) - receivedp = typecheck(receivedp, Erv) + receivedp = typecheck(receivedp, ctxExpr) r.Left = mkcall1(chanfn("selectnbrecv2", 2, ch.Type), types.Types[TBOOL], &r.Ninit, elem, receivedp, ch) } - r.Left = typecheck(r.Left, Erv) + r.Left = typecheck(r.Left, ctxExpr) r.Nbody.Set(cas.Nbody.Slice()) r.Rlist.Set(append(dflt.Ninit.Slice(), dflt.Nbody.Slice()...)) return []*Node{r, nod(OBREAK, nil, nil)} @@ -265,12 +265,12 @@ func walkselectcases(cases *Nodes) []*Node { lineno = sellineno selv := temp(types.NewArray(scasetype(), int64(n))) r := nod(OAS, selv, nil) - r = typecheck(r, Etop) + r = typecheck(r, ctxStmt) init = append(init, r) order := temp(types.NewArray(types.Types[TUINT16], 2*int64(n))) r = nod(OAS, order, nil) - r = typecheck(r, Etop) + r = typecheck(r, ctxStmt) init = append(init, r) // register cases @@ -310,7 +310,7 @@ func walkselectcases(cases *Nodes) []*Node { setField := func(f string, val *Node) { r := nod(OAS, nodSym(ODOT, nod(OINDEX, selv, nodintconst(int64(i))), lookup(f)), val) - r = typecheck(r, Etop) + r = typecheck(r, ctxStmt) init = append(init, r) } @@ -340,7 +340,7 @@ func walkselectcases(cases *Nodes) []*Node { r.List.Set2(chosen, recvOK) fn := syslook("selectgo") r.Rlist.Set1(mkcall1(fn, fn.Type.Results(), nil, bytePtrToIndex(selv, 0), bytePtrToIndex(order, 0), nodintconst(int64(n)))) - r = typecheck(r, Etop) + r = typecheck(r, ctxStmt) init = append(init, r) // selv and order are no longer alive after selectgo. @@ -352,14 +352,14 @@ func walkselectcases(cases *Nodes) []*Node { setlineno(cas) cond := nod(OEQ, chosen, nodintconst(int64(i))) - cond = typecheck(cond, Erv) + cond = typecheck(cond, ctxExpr) cond = defaultlit(cond, nil) r = nod(OIF, cond, nil) if n := cas.Left; n != nil && n.Op == OSELRECV2 { x := nod(OAS, n.List.First(), recvOK) - x = typecheck(x, Etop) + x = typecheck(x, ctxStmt) r.Nbody.Append(x) } diff --git a/src/cmd/compile/internal/gc/sinit.go b/src/cmd/compile/internal/gc/sinit.go index ac8dbf60173f50..28ea72b715a3c6 100644 --- a/src/cmd/compile/internal/gc/sinit.go +++ b/src/cmd/compile/internal/gc/sinit.go @@ -411,7 +411,7 @@ func staticassign(l *Node, r *Node, out *[]*Node) bool { } //dump("not static ptrlit", r); - case OSTRARRAYBYTE: + case OSTR2BYTES: if l.Class() == PEXTERN && r.Left.Op == OLITERAL { sval := r.Left.Val().U.(string) slicebytes(l, sval, len(sval)) @@ -585,7 +585,7 @@ func (n *Node) isSimpleName() bool { func litas(l *Node, r *Node, init *Nodes) { a := nod(OAS, l, r) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) a = walkexpr(a, init) init.Append(a) } @@ -746,7 +746,7 @@ func fixedlit(ctxt initContext, kind initKind, n *Node, var_ *Node, init *Nodes) // build list of assignments: var[index] = expr setlineno(value) a = nod(OAS, a, value) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) switch kind { case initKindStatic: genAsStatic(a) @@ -774,7 +774,7 @@ func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) { fixedlit(ctxt, initKindDynamic, n, vstat, init) // copy static to slice - var_ = typecheck(var_, Erv|Easgn) + var_ = typecheck(var_, ctxExpr|ctxAssign) var nam Node if !stataddr(&nam, var_) || nam.Class() != PEXTERN { Fatalf("slicelit: %v", var_) @@ -839,7 +839,7 @@ func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) { if vstat == nil { a = nod(OAS, x, nil) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) init.Append(a) // zero new temp } else { // Declare that we're about to initialize all of x. @@ -852,7 +852,7 @@ func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) { a = temp(t) if vstat == nil { a = nod(OAS, temp(t), nil) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) init.Append(a) // zero new temp a = a.Left } else { @@ -866,16 +866,16 @@ func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) { } a = nod(OAS, vauto, a) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) a = walkexpr(a, init) init.Append(a) if vstat != nil { // copy static to heap (4) - a = nod(OIND, vauto, nil) + a = nod(ODEREF, vauto, nil) a = nod(OAS, a, vstat) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) a = walkexpr(a, init) init.Append(a) } @@ -910,7 +910,7 @@ func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) { setlineno(value) a = nod(OAS, a, value) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) a = orderStmtInPlace(a, map[string][]*Node{}) a = walkstmt(a) init.Append(a) @@ -919,7 +919,7 @@ func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) { // make slice out of heap (6) a = nod(OAS, var_, nod(OSLICE, vauto, nil)) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) a = orderStmtInPlace(a, map[string][]*Node{}) a = walkstmt(a) init.Append(a) @@ -993,7 +993,7 @@ func maplit(n *Node, m *Node, init *Nodes) { loop.Nbody.Set1(body) loop.Ninit.Set1(zero) - loop = typecheck(loop, Etop) + loop = typecheck(loop, ctxStmt) loop = walkstmt(loop) init.Append(loop) } else { @@ -1023,19 +1023,19 @@ func addMapEntries(m *Node, dyn []*Node, init *Nodes) { setlineno(index) a := nod(OAS, key, index) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) a = walkstmt(a) init.Append(a) setlineno(value) a = nod(OAS, val, value) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) a = walkstmt(a) init.Append(a) setlineno(val) a = nod(OAS, nod(OINDEX, m, key), val) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) a = walkstmt(a) init.Append(a) @@ -1045,10 +1045,10 @@ func addMapEntries(m *Node, dyn []*Node, init *Nodes) { } a := nod(OVARKILL, key, nil) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) init.Append(a) a = nod(OVARKILL, val, nil) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) init.Append(a) } @@ -1068,7 +1068,7 @@ func anylit(n *Node, var_ *Node, init *Nodes) { // n.Right is stack temporary used as backing store. init.Append(nod(OAS, n.Right, nil)) // zero backing store, just in case (#18410) r = nod(OADDR, n.Right, nil) - r = typecheck(r, Erv) + r = typecheck(r, ctxExpr) } else { r = nod(ONEW, nil, nil) r.SetTypecheck(1) @@ -1079,11 +1079,11 @@ func anylit(n *Node, var_ *Node, init *Nodes) { r = walkexpr(r, init) a := nod(OAS, var_, r) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) init.Append(a) - var_ = nod(OIND, var_, nil) - var_ = typecheck(var_, Erv|Easgn) + var_ = nod(ODEREF, var_, nil) + var_ = typecheck(var_, ctxExpr|ctxAssign) anylit(n.Left, var_, init) case OSTRUCTLIT, OARRAYLIT: @@ -1105,7 +1105,7 @@ func anylit(n *Node, var_ *Node, init *Nodes) { // copy static to var a := nod(OAS, var_, vstat) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) a = walkexpr(a, init) init.Append(a) @@ -1123,7 +1123,7 @@ func anylit(n *Node, var_ *Node, init *Nodes) { // initialization of an array or struct with unspecified components (missing fields or arrays) if var_.isSimpleName() || int64(n.List.Len()) < components { a := nod(OAS, var_, nil) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) a = walkexpr(a, init) init.Append(a) } diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 1c64c6437d4b2e..7a4152a9e6d489 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -803,7 +803,7 @@ func (s *state) stmt(n *Node) { } case ODEFER: s.call(n.Left, callDefer) - case OPROC: + case OGO: s.call(n.Left, callGo) case OAS2DOTTYPE: @@ -1268,25 +1268,25 @@ var opToSSA = map[opAndType]ssa.Op{ opAndType{ONOT, TBOOL}: ssa.OpNot, - opAndType{OMINUS, TINT8}: ssa.OpNeg8, - opAndType{OMINUS, TUINT8}: ssa.OpNeg8, - opAndType{OMINUS, TINT16}: ssa.OpNeg16, - opAndType{OMINUS, TUINT16}: ssa.OpNeg16, - opAndType{OMINUS, TINT32}: ssa.OpNeg32, - opAndType{OMINUS, TUINT32}: ssa.OpNeg32, - opAndType{OMINUS, TINT64}: ssa.OpNeg64, - opAndType{OMINUS, TUINT64}: ssa.OpNeg64, - opAndType{OMINUS, TFLOAT32}: ssa.OpNeg32F, - opAndType{OMINUS, TFLOAT64}: ssa.OpNeg64F, - - opAndType{OCOM, TINT8}: ssa.OpCom8, - opAndType{OCOM, TUINT8}: ssa.OpCom8, - opAndType{OCOM, TINT16}: ssa.OpCom16, - opAndType{OCOM, TUINT16}: ssa.OpCom16, - opAndType{OCOM, TINT32}: ssa.OpCom32, - opAndType{OCOM, TUINT32}: ssa.OpCom32, - opAndType{OCOM, TINT64}: ssa.OpCom64, - opAndType{OCOM, TUINT64}: ssa.OpCom64, + opAndType{ONEG, TINT8}: ssa.OpNeg8, + opAndType{ONEG, TUINT8}: ssa.OpNeg8, + opAndType{ONEG, TINT16}: ssa.OpNeg16, + opAndType{ONEG, TUINT16}: ssa.OpNeg16, + opAndType{ONEG, TINT32}: ssa.OpNeg32, + opAndType{ONEG, TUINT32}: ssa.OpNeg32, + opAndType{ONEG, TINT64}: ssa.OpNeg64, + opAndType{ONEG, TUINT64}: ssa.OpNeg64, + opAndType{ONEG, TFLOAT32}: ssa.OpNeg32F, + opAndType{ONEG, TFLOAT64}: ssa.OpNeg64F, + + opAndType{OBITNOT, TINT8}: ssa.OpCom8, + opAndType{OBITNOT, TUINT8}: ssa.OpCom8, + opAndType{OBITNOT, TINT16}: ssa.OpCom16, + opAndType{OBITNOT, TUINT16}: ssa.OpCom16, + opAndType{OBITNOT, TINT32}: ssa.OpCom32, + opAndType{OBITNOT, TUINT32}: ssa.OpCom32, + opAndType{OBITNOT, TINT64}: ssa.OpCom64, + opAndType{OBITNOT, TUINT64}: ssa.OpCom64, opAndType{OIMAG, TCOMPLEX64}: ssa.OpComplexImag, opAndType{OIMAG, TCOMPLEX128}: ssa.OpComplexImag, @@ -1655,12 +1655,12 @@ func (s *state) expr(n *Node) *ssa.Value { s.stmtList(n.Ninit) switch n.Op { - case OARRAYBYTESTRTMP: + case OBYTES2STRTMP: slice := s.expr(n.Left) ptr := s.newValue1(ssa.OpSlicePtr, s.f.Config.Types.BytePtr, slice) len := s.newValue1(ssa.OpSliceLen, types.Types[TINT], slice) return s.newValue2(ssa.OpStringMake, n.Type, ptr, len) - case OSTRARRAYBYTETMP: + case OSTR2BYTESTMP: str := s.expr(n.Left) ptr := s.newValue1(ssa.OpStringPtr, s.f.Config.Types.BytePtr, str) len := s.newValue1(ssa.OpStringLen, types.Types[TINT], str) @@ -2174,7 +2174,7 @@ func (s *state) expr(n *Node) *ssa.Value { return s.newValue2(ssa.OpComplexMake, n.Type, r, i) // unary ops - case OMINUS: + case ONEG: a := s.expr(n.Left) if n.Type.IsComplex() { tp := floatForComplex(n.Type) @@ -2184,7 +2184,7 @@ func (s *state) expr(n *Node) *ssa.Value { s.newValue1(negop, tp, s.newValue1(ssa.OpComplexImag, tp, a))) } return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a) - case ONOT, OCOM: + case ONOT, OBITNOT: a := s.expr(n.Left) return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a) case OIMAG, OREAL: @@ -2200,7 +2200,7 @@ func (s *state) expr(n *Node) *ssa.Value { addr := s.constOffPtrSP(types.NewPtr(n.Type), n.Xoffset) return s.load(n.Type, addr) - case OIND: + case ODEREF: p := s.exprPtr(n.Left, false, n.Pos) return s.load(n.Type, p) @@ -2838,7 +2838,7 @@ func (s *state) sfcall(op ssa.Op, args ...*ssa.Value) (*ssa.Value, bool) { args[0], args[1] = args[1], args[0] case ssa.OpSub32F, ssa.OpSub64F: - args[1] = s.newValue1(s.ssaOp(OMINUS, types.Types[callDef.rtype]), args[1].Type, args[1]) + args[1] = s.newValue1(s.ssaOp(ONEG, types.Types[callDef.rtype]), args[1].Type, args[1]) } result := s.rtcall(callDef.rtfn, true, []*types.Type{types.Types[callDef.rtype]}, args...)[0] @@ -2915,7 +2915,7 @@ func init() { if !instrumenting { add("runtime", "slicebytetostringtmp", func(s *state, n *Node, args []*ssa.Value) *ssa.Value { - // Compiler frontend optimizations emit OARRAYBYTESTRTMP nodes + // Compiler frontend optimizations emit OBYTES2STRTMP nodes // for the backend instead of slicebytetostringtmp calls // when not instrumenting. slice := args[0] @@ -3861,7 +3861,7 @@ func (s *state) addr(n *Node, bounded bool) *ssa.Value { } return s.newValue2(ssa.OpPtrIndex, types.NewPtr(n.Left.Type.Elem()), a, i) } - case OIND: + case ODEREF: return s.exprPtr(n.Left, bounded, n.Pos) case ODOT: p := s.addr(n.Left, bounded) diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go index 127e5fdc77997f..629186829a5af4 100644 --- a/src/cmd/compile/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -767,10 +767,10 @@ func convertop(src *types.Type, dst *types.Type, why *string) Op { if src.IsSlice() && dst.IsString() { if src.Elem().Etype == types.Bytetype.Etype { - return OARRAYBYTESTR + return OBYTES2STR } if src.Elem().Etype == types.Runetype.Etype { - return OARRAYRUNESTR + return ORUNES2STR } } @@ -778,10 +778,10 @@ func convertop(src *types.Type, dst *types.Type, why *string) Op { // String to slice. if src.IsString() && dst.IsSlice() { if dst.Elem().Etype == types.Bytetype.Etype { - return OSTRARRAYBYTE + return OSTR2BYTES } if dst.Elem().Etype == types.Runetype.Etype { - return OSTRARRAYRUNE + return OSTR2RUNES } } @@ -999,14 +999,14 @@ func calcHasCall(n *Node) bool { return true } case OINDEX, OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR, - OIND, ODOTPTR, ODOTTYPE, ODIV, OMOD: + ODEREF, ODOTPTR, ODOTTYPE, ODIV, OMOD: // These ops might panic, make sure they are done // before we start marshaling args for a call. See issue 16760. return true // When using soft-float, these ops might be rewritten to function calls // so we ensure they are evaluated first. - case OADD, OSUB, OMINUS, OMUL: + case OADD, OSUB, ONEG, OMUL: if thearch.SoftFloat && (isFloat[n.Type.Etype] || isComplex[n.Type.Etype]) { return true } @@ -1116,11 +1116,11 @@ func safeexpr(n *Node, init *Nodes) *Node { } r := n.copy() r.Left = l - r = typecheck(r, Erv) + r = typecheck(r, ctxExpr) r = walkexpr(r, init) return r - case ODOTPTR, OIND: + case ODOTPTR, ODEREF: l := safeexpr(n.Left, init) if l == n.Left { return n @@ -1158,7 +1158,7 @@ func safeexpr(n *Node, init *Nodes) *Node { func copyexpr(n *Node, t *types.Type, init *Nodes) *Node { l := temp(t) a := nod(OAS, l, n) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) a = walkexpr(a, init) init.Append(a) return l @@ -1308,7 +1308,7 @@ func dotpath(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool) ( // will give shortest unique addressing. // modify the tree with missing type names. func adddot(n *Node) *Node { - n.Left = typecheck(n.Left, Etype|Erv) + n.Left = typecheck(n.Left, Etype|ctxExpr) if n.Left.Diag() { n.SetDiag(true) } @@ -1478,7 +1478,7 @@ func structargs(tl *types.Type, mustname bool) []*Node { } a := symfield(s, t.Type) a.Pos = t.Pos - a.SetIsddd(t.Isddd()) + a.SetIsDDD(t.IsDDD()) args = append(args, a) } @@ -1571,7 +1571,7 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) { fn.Func.SetWrapper(true) // ignore frame for panic+recover matching call := nod(OCALL, dot, nil) call.List.Set(paramNnames(tfn.Type)) - call.SetIsddd(tfn.Type.IsVariadic()) + call.SetIsDDD(tfn.Type.IsVariadic()) if method.Type.NumResults() > 0 { n := nod(ORETURN, nil, nil) n.List.Set1(call) @@ -1589,10 +1589,10 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) { testdclstack() } - fn = typecheck(fn, Etop) + fn = typecheck(fn, ctxStmt) Curfn = fn - typecheckslice(fn.Nbody.Slice(), Etop) + typecheckslice(fn.Nbody.Slice(), ctxStmt) // Inline calls within (*T).M wrappers. This is safe because we only // generate those wrappers within the same compilation unit as (T).M. @@ -1852,7 +1852,7 @@ func checknil(x *Node, init *Nodes) { x = walkexpr(x, nil) // caller has not done this yet if x.Type.IsInterface() { x = nod(OITAB, x, nil) - x = typecheck(x, Erv) + x = typecheck(x, ctxExpr) } n := nod(OCHECKNIL, x, nil) @@ -1910,7 +1910,7 @@ func ifaceData(n *Node, t *types.Type) *Node { ptr.Type = types.NewPtr(t) ptr.SetBounded(true) ptr.SetTypecheck(1) - ind := nod(OIND, ptr, nil) + ind := nod(ODEREF, ptr, nil) ind.Type = t ind.SetTypecheck(1) return ind diff --git a/src/cmd/compile/internal/gc/swt.go b/src/cmd/compile/internal/gc/swt.go index f1c153937fba59..b475e7adc3d57e 100644 --- a/src/cmd/compile/internal/gc/swt.go +++ b/src/cmd/compile/internal/gc/swt.go @@ -56,7 +56,7 @@ type caseClauses struct { // typecheckswitch typechecks a switch statement. func typecheckswitch(n *Node) { - typecheckslice(n.Ninit.Slice(), Etop) + typecheckslice(n.Ninit.Slice(), ctxStmt) var nilonly string var top int @@ -65,7 +65,7 @@ func typecheckswitch(n *Node) { if n.Left != nil && n.Left.Op == OTYPESW { // type switch top = Etype - n.Left.Right = typecheck(n.Left.Right, Erv) + n.Left.Right = typecheck(n.Left.Right, ctxExpr) t = n.Left.Right.Type if t != nil && !t.IsInterface() { yyerrorl(n.Pos, "cannot type switch on non-interface value %L", n.Left.Right) @@ -78,9 +78,9 @@ func typecheckswitch(n *Node) { } } else { // expression switch - top = Erv + top = ctxExpr if n.Left != nil { - n.Left = typecheck(n.Left, Erv) + n.Left = typecheck(n.Left, ctxExpr) n.Left = defaultlit(n.Left, nil) t = n.Left.Type } else { @@ -122,7 +122,7 @@ func typecheckswitch(n *Node) { ls := ncase.List.Slice() for i1, n1 := range ls { setlineno(n1) - ls[i1] = typecheck(ls[i1], Erv|Etype) + ls[i1] = typecheck(ls[i1], ctxExpr|Etype) n1 = ls[i1] if n1.Type == nil || t == nil { continue @@ -131,7 +131,7 @@ func typecheckswitch(n *Node) { setlineno(ncase) switch top { // expression switch - case Erv: + case ctxExpr: ls[i1] = defaultlit(ls[i1], t) n1 = ls[i1] switch { @@ -203,16 +203,16 @@ func typecheckswitch(n *Node) { nvar.Type = n.Type } - nvar = typecheck(nvar, Erv|Easgn) + nvar = typecheck(nvar, ctxExpr|ctxAssign) ncase.Rlist.SetFirst(nvar) } } - typecheckslice(ncase.Nbody.Slice(), Etop) + typecheckslice(ncase.Nbody.Slice(), ctxStmt) } switch top { // expression switch - case Erv: + case ctxExpr: checkDupExprCases(n.Left, n.List.Slice()) } } @@ -222,7 +222,7 @@ func walkswitch(sw *Node) { // convert switch {...} to switch true {...} if sw.Left == nil { sw.Left = nodbool(true) - sw.Left = typecheck(sw.Left, Erv) + sw.Left = typecheck(sw.Left, ctxExpr) sw.Left = defaultlit(sw.Left, nil) } @@ -271,7 +271,7 @@ func (s *exprSwitch) walk(sw *Node) { // because walkexpr will lower the string // conversion into a runtime call. // See issue 24937 for more discussion. - if cond.Op == OARRAYBYTESTR { + if cond.Op == OBYTES2STR { ok := true for _, cas := range sw.List.Slice() { if cas.Op != OCASE { @@ -283,7 +283,7 @@ func (s *exprSwitch) walk(sw *Node) { } } if ok { - cond.Op = OARRAYBYTESTRTMP + cond.Op = OBYTES2STRTMP } } @@ -303,7 +303,7 @@ func (s *exprSwitch) walk(sw *Node) { } else { s.exprname = temp(cond.Type) cas = []*Node{nod(OAS, s.exprname, cond)} - typecheckslice(cas, Etop) + typecheckslice(cas, ctxStmt) } // Enumerate the cases and prepare the default case. @@ -362,7 +362,7 @@ func (s *exprSwitch) walkCases(cc []caseClause) *Node { // s.kind == switchKindFalse a.Left = nod(ONOT, n.Left, nil) // if !val } - a.Left = typecheck(a.Left, Erv) + a.Left = typecheck(a.Left, ctxExpr) a.Left = defaultlit(a.Left, nil) a.Nbody.Set1(n.Right) // goto l @@ -391,7 +391,7 @@ func (s *exprSwitch) walkCases(cc []caseClause) *Node { } else { a.Left = le } - a.Left = typecheck(a.Left, Erv) + a.Left = typecheck(a.Left, ctxExpr) a.Left = defaultlit(a.Left, nil) a.Nbody.Set1(s.walkCases(cc[:half])) a.Rlist.Set1(s.walkCases(cc[half:])) @@ -493,7 +493,7 @@ func casebody(sw *Node, typeswvar *Node) { nod(ODCL, n.Rlist.First(), nil), nod(OAS, n.Rlist.First(), typeswvar), } - typecheckslice(l, Etop) + typecheckslice(l, ctxStmt) stat = append(stat, l...) } stat = append(stat, n.Nbody.Slice()...) @@ -742,14 +742,14 @@ func (s *typeSwitch) walk(sw *Node) { s.facename = temp(cond.Right.Type) a := nod(OAS, s.facename, cond.Right) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) cas = append(cas, a) s.okname = temp(types.Types[TBOOL]) - s.okname = typecheck(s.okname, Erv) + s.okname = typecheck(s.okname, ctxExpr) s.hashname = temp(types.Types[TUINT32]) - s.hashname = typecheck(s.hashname, Erv) + s.hashname = typecheck(s.hashname, ctxExpr) // set up labels and jumps casebody(sw, s.facename) @@ -785,7 +785,7 @@ func (s *typeSwitch) walk(sw *Node) { blk.List.Set2(nodSym(OLABEL, nil, lbl), def) def = blk } - i.Left = typecheck(i.Left, Erv) + i.Left = typecheck(i.Left, ctxExpr) i.Left = defaultlit(i.Left, nil) cas = append(cas, i) @@ -800,7 +800,7 @@ func (s *typeSwitch) walk(sw *Node) { } h.SetBounded(true) // guaranteed not to fault a = nod(OAS, s.hashname, h) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) cas = append(cas, a) cc := clauses.list @@ -868,12 +868,12 @@ func (s *typeSwitch) typeone(t *Node) *Node { var init Nodes if t.Rlist.Len() == 0 { name = nblank - nblank = typecheck(nblank, Erv|Easgn) + nblank = typecheck(nblank, ctxExpr|ctxAssign) } else { name = t.Rlist.First() init.Append(nod(ODCL, name, nil)) a := nod(OAS, name, nil) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) init.Append(a) } @@ -882,7 +882,7 @@ func (s *typeSwitch) typeone(t *Node) *Node { b := nod(ODOTTYPE, s.facename, nil) b.Type = t.Left.Type // interface.(type) a.Rlist.Set1(b) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) a = walkexpr(a, &init) init.Append(a) @@ -905,7 +905,7 @@ func (s *typeSwitch) walkCases(cc []caseClause) *Node { } a := nod(OIF, nil, nil) a.Left = nod(OEQ, s.hashname, nodintconst(int64(c.hash))) - a.Left = typecheck(a.Left, Erv) + a.Left = typecheck(a.Left, ctxExpr) a.Left = defaultlit(a.Left, nil) a.Nbody.Set1(n.Right) cas = append(cas, a) @@ -917,7 +917,7 @@ func (s *typeSwitch) walkCases(cc []caseClause) *Node { half := len(cc) / 2 a := nod(OIF, nil, nil) a.Left = nod(OLE, s.hashname, nodintconst(int64(cc[half-1].hash))) - a.Left = typecheck(a.Left, Erv) + a.Left = typecheck(a.Left, ctxExpr) a.Left = defaultlit(a.Left, nil) a.Nbody.Set1(s.walkCases(cc[:half])) a.Rlist.Set1(s.walkCases(cc[half:])) diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go index e29a3d7657d9b0..9ecea8a4c526e1 100644 --- a/src/cmd/compile/internal/gc/syntax.go +++ b/src/cmd/compile/internal/gc/syntax.go @@ -144,7 +144,7 @@ const ( _, nodeAssigned // is the variable ever assigned to _, nodeAddrtaken // address taken, even if not moved to heap _, nodeImplicit - _, nodeIsddd // is the argument variadic + _, nodeIsDDD // is the argument variadic _, nodeDiag // already printed error about this _, nodeColas // OAS resulting from := _, nodeNonNil // guaranteed to be non-nil @@ -172,7 +172,7 @@ func (n *Node) IsOutputParamHeapAddr() bool { return n.flags&nodeIsOutputParamHe func (n *Node) Assigned() bool { return n.flags&nodeAssigned != 0 } func (n *Node) Addrtaken() bool { return n.flags&nodeAddrtaken != 0 } func (n *Node) Implicit() bool { return n.flags&nodeImplicit != 0 } -func (n *Node) Isddd() bool { return n.flags&nodeIsddd != 0 } +func (n *Node) IsDDD() bool { return n.flags&nodeIsDDD != 0 } func (n *Node) Diag() bool { return n.flags&nodeDiag != 0 } func (n *Node) Colas() bool { return n.flags&nodeColas != 0 } func (n *Node) NonNil() bool { return n.flags&nodeNonNil != 0 } @@ -199,7 +199,7 @@ func (n *Node) SetIsOutputParamHeapAddr(b bool) { n.flags.set(nodeIsOutputParamH func (n *Node) SetAssigned(b bool) { n.flags.set(nodeAssigned, b) } func (n *Node) SetAddrtaken(b bool) { n.flags.set(nodeAddrtaken, b) } func (n *Node) SetImplicit(b bool) { n.flags.set(nodeImplicit, b) } -func (n *Node) SetIsddd(b bool) { n.flags.set(nodeIsddd, b) } +func (n *Node) SetIsDDD(b bool) { n.flags.set(nodeIsDDD, b) } func (n *Node) SetDiag(b bool) { n.flags.set(nodeDiag, b) } func (n *Node) SetColas(b bool) { n.flags.set(nodeColas, b) } func (n *Node) SetNonNil(b bool) { n.flags.set(nodeNonNil, b) } @@ -477,7 +477,7 @@ type Func struct { FieldTrack map[*types.Sym]struct{} DebugInfo *ssa.FuncDebug Ntype *Node // signature - Top int // top context (Ecall, Eproc, etc) + Top int // top context (ctxCallee, etc) Closure *Node // OCLOSURE <-> ODCLFUNC Nname *Node lsym *obj.LSym @@ -581,28 +581,28 @@ const ( OLITERAL // literal // expressions - OADD // Left + Right - OSUB // Left - Right - OOR // Left | Right - OXOR // Left ^ Right - OADDSTR // +{List} (string addition, list elements are strings) - OADDR // &Left - OANDAND // Left && Right - OAPPEND // append(List); after walk, Left may contain elem type descriptor - OARRAYBYTESTR // Type(Left) (Type is string, Left is a []byte) - OARRAYBYTESTRTMP // Type(Left) (Type is string, Left is a []byte, ephemeral) - OARRAYRUNESTR // Type(Left) (Type is string, Left is a []rune) - OSTRARRAYBYTE // Type(Left) (Type is []byte, Left is a string) - OSTRARRAYBYTETMP // Type(Left) (Type is []byte, Left is a string, ephemeral) - OSTRARRAYRUNE // Type(Left) (Type is []rune, Left is a string) - OAS // Left = Right or (if Colas=true) Left := Right - OAS2 // List = Rlist (x, y, z = a, b, c) - OAS2FUNC // List = Rlist (x, y = f()) - OAS2RECV // List = Rlist (x, ok = <-c) - OAS2MAPR // List = Rlist (x, ok = m["foo"]) - OAS2DOTTYPE // List = Rlist (x, ok = I.(int)) - OASOP // Left Etype= Right (x += y) - OCALL // Left(List) (function call, method call or type conversion) + OADD // Left + Right + OSUB // Left - Right + OOR // Left | Right + OXOR // Left ^ Right + OADDSTR // +{List} (string addition, list elements are strings) + OADDR // &Left + OANDAND // Left && Right + OAPPEND // append(List); after walk, Left may contain elem type descriptor + OBYTES2STR // Type(Left) (Type is string, Left is a []byte) + OBYTES2STRTMP // Type(Left) (Type is string, Left is a []byte, ephemeral) + ORUNES2STR // Type(Left) (Type is string, Left is a []rune) + OSTR2BYTES // Type(Left) (Type is []byte, Left is a string) + OSTR2BYTESTMP // Type(Left) (Type is []byte, Left is a string, ephemeral) + OSTR2RUNES // Type(Left) (Type is []rune, Left is a string) + OAS // Left = Right or (if Colas=true) Left := Right + OAS2 // List = Rlist (x, y, z = a, b, c) + OAS2FUNC // List = Rlist (x, y = f()) + OAS2RECV // List = Rlist (x, ok = <-c) + OAS2MAPR // List = Rlist (x, ok = m["foo"]) + OAS2DOTTYPE // List = Rlist (x, ok = I.(int)) + OASOP // Left Etype= Right (x += y) + OCALL // Left(List) (function call, method call or type conversion) // OCALLFUNC, OCALLMETH, and OCALLINTER have the same structure. // Prior to walk, they are: Left(List), where List is all regular arguments. @@ -650,7 +650,7 @@ const ( OLE // Left <= Right OGE // Left >= Right OGT // Left > Right - OIND // *Left + ODEREF // *Left OINDEX // Left[Right] (index of array or slice) OINDEXMAP // Left[Right] (index of map) OKEY // Left:Right (key:value in struct/array/map literal) @@ -669,9 +669,9 @@ const ( OANDNOT // Left &^ Right ONEW // new(Left) ONOT // !Left - OCOM // ^Left + OBITNOT // ^Left OPLUS // +Left - OMINUS // -Left + ONEG // -Left OOROR // Left || Right OPANIC // panic(Left) OPRINT // print(List) @@ -720,7 +720,7 @@ const ( OGOTO // goto Sym OIF // if Ninit; Left { Nbody } else { Rlist } OLABEL // Sym: - OPROC // go Left (Left must be call) + OGO // go Left (Left must be call) ORANGE // for List = range Right { Nbody } ORETURN // return List OSELECT // select { List } (List is list of OXCASE or OCASE) diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index 371e0924e71551..069a38cbbbe19d 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -57,13 +57,13 @@ func tracePrint(title string, n *Node) func(np **Node) { } const ( - Etop = 1 << iota // evaluated at statement level - Erv // evaluated in value context - Etype // evaluated in type context - Ecall // call-only expressions are ok - Efnstruct // multivalue function returns are ok - Easgn // assigning to expression - Ecomplit // type in composite literal + ctxStmt = 1 << iota // evaluated at statement level + ctxExpr // evaluated in value context + Etype // evaluated in type context + ctxCallee // call-only expressions are ok + ctxMultiOK // multivalue function returns are ok + ctxAssign // assigning to expression + ctxCompLit // type in composite literal ) // type checks the whole tree of an expression. @@ -243,7 +243,7 @@ func typecheck(n *Node, top int) (res *Node) { switch n.Op { // We can already diagnose variables used as types. case ONAME: - if top&(Erv|Etype) == Etype { + if top&(ctxExpr|Etype) == Etype { yyerror("%v is not a type", n) } @@ -273,7 +273,7 @@ func typecheck(n *Node, top int) (res *Node) { } case OLITERAL: - if top&(Erv|Etype) == Etype { + if top&(ctxExpr|Etype) == Etype { yyerror("%v is not a type", n) break } @@ -367,7 +367,7 @@ func typecheck1(n *Node, top int) (res *Node) { break } - if n.Op == ONAME && n.SubOp() != 0 && top&Ecall == 0 { + if n.Op == ONAME && n.SubOp() != 0 && top&ctxCallee == 0 { yyerror("use of builtin %v not in function call", n.Sym) n.Type = nil return n @@ -390,25 +390,25 @@ func typecheck1(n *Node, top int) (res *Node) { // names case OLITERAL: - ok |= Erv + ok |= ctxExpr if n.Type == nil && n.Val().Ctype() == CTSTR { n.Type = types.Idealstring } case ONONAME: - ok |= Erv + ok |= ctxExpr case ONAME: if n.Name.Decldepth == 0 { n.Name.Decldepth = decldepth } if n.SubOp() != 0 { - ok |= Ecall + ok |= ctxCallee break } - if top&Easgn == 0 { + if top&ctxAssign == 0 { // not a write to the variable if n.isBlank() { yyerror("cannot use _ as value") @@ -419,7 +419,7 @@ func typecheck1(n *Node, top int) (res *Node) { n.Name.SetUsed(true) } - ok |= Erv + ok |= ctxExpr case OPACK: yyerror("use of package %v without selector", n.Sym) @@ -429,7 +429,7 @@ func typecheck1(n *Node, top int) (res *Node) { case ODDD: break - // types (OIND is with exprs) + // types (ODEREF is with exprs) case OTYPE: ok |= Etype @@ -449,7 +449,7 @@ func typecheck1(n *Node, top int) (res *Node) { if n.Left == nil { t = types.NewSlice(r.Type) } else if n.Left.Op == ODDD { - if top&Ecomplit == 0 { + if top&ctxCompLit == 0 { if !n.Diag() { n.SetDiag(true) yyerror("use of [...] array outside of array literal") @@ -459,7 +459,7 @@ func typecheck1(n *Node, top int) (res *Node) { } t = types.NewDDDArray(r.Type) } else { - n.Left = indexlit(typecheck(n.Left, Erv)) + n.Left = indexlit(typecheck(n.Left, ctxExpr)) l := n.Left if consttype(l) != CTINT { switch { @@ -567,8 +567,8 @@ func typecheck1(n *Node, top int) (res *Node) { n.Rlist.Set(nil) // type or expr - case OIND: - n.Left = typecheck(n.Left, Erv|Etype|top&Ecomplit) + case ODEREF: + n.Left = typecheck(n.Left, ctxExpr|Etype|top&ctxCompLit) l := n.Left t := l.Type if t == nil { @@ -590,7 +590,7 @@ func typecheck1(n *Node, top int) (res *Node) { } if !t.IsPtr() { - if top&(Erv|Etop) != 0 { + if top&(ctxExpr|ctxStmt) != 0 { yyerror("invalid indirect of %L", n.Left) n.Type = nil return n @@ -599,7 +599,7 @@ func typecheck1(n *Node, top int) (res *Node) { break } - ok |= Erv + ok |= ctxExpr n.Type = t.Elem() // arithmetic exprs @@ -627,9 +627,9 @@ func typecheck1(n *Node, top int) (res *Node) { var op Op var r *Node if n.Op == OASOP { - ok |= Etop - n.Left = typecheck(n.Left, Erv) - n.Right = typecheck(n.Right, Erv) + ok |= ctxStmt + n.Left = typecheck(n.Left, ctxExpr) + n.Right = typecheck(n.Right, ctxExpr) l = n.Left r = n.Right checkassign(n, n.Left) @@ -645,9 +645,9 @@ func typecheck1(n *Node, top int) (res *Node) { // TODO(marvin): Fix Node.EType type union. op = n.SubOp() } else { - ok |= Erv - n.Left = typecheck(n.Left, Erv) - n.Right = typecheck(n.Right, Erv) + ok |= ctxExpr + n.Left = typecheck(n.Left, ctxExpr) + n.Right = typecheck(n.Right, ctxExpr) l = n.Left r = n.Right if l.Type == nil || r.Type == nil { @@ -841,9 +841,9 @@ func typecheck1(n *Node, top int) (res *Node) { n.Type = t - case OCOM, OMINUS, ONOT, OPLUS: - ok |= Erv - n.Left = typecheck(n.Left, Erv) + case OBITNOT, ONEG, ONOT, OPLUS: + ok |= ctxExpr + n.Left = typecheck(n.Left, ctxExpr) l := n.Left t := l.Type if t == nil { @@ -860,9 +860,9 @@ func typecheck1(n *Node, top int) (res *Node) { // exprs case OADDR: - ok |= Erv + ok |= ctxExpr - n.Left = typecheck(n.Left, Erv) + n.Left = typecheck(n.Left, ctxExpr) if n.Left.Type == nil { n.Type = nil return n @@ -899,7 +899,7 @@ func typecheck1(n *Node, top int) (res *Node) { n.Type = types.NewPtr(t) case OCOMPLIT: - ok |= Erv + ok |= ctxExpr n = typecheckcomplit(n) if n.Type == nil { return n @@ -915,7 +915,7 @@ func typecheck1(n *Node, top int) (res *Node) { } } - n.Left = typecheck(n.Left, Erv|Etype) + n.Left = typecheck(n.Left, ctxExpr|Etype) n.Left = defaultlit(n.Left, nil) @@ -933,7 +933,7 @@ func typecheck1(n *Node, top int) (res *Node) { if n.Type == nil { return n } - ok = Erv + ok = ctxExpr break } @@ -980,20 +980,20 @@ func typecheck1(n *Node, top int) (res *Node) { switch n.Op { case ODOTINTER, ODOTMETH: - if top&Ecall != 0 { - ok |= Ecall + if top&ctxCallee != 0 { + ok |= ctxCallee } else { typecheckpartialcall(n, s) - ok |= Erv + ok |= ctxExpr } default: - ok |= Erv + ok |= ctxExpr } case ODOTTYPE: - ok |= Erv - n.Left = typecheck(n.Left, Erv) + ok |= ctxExpr + n.Left = typecheck(n.Left, ctxExpr) n.Left = defaultlit(n.Left, nil) l := n.Left t := l.Type @@ -1037,12 +1037,12 @@ func typecheck1(n *Node, top int) (res *Node) { } case OINDEX: - ok |= Erv - n.Left = typecheck(n.Left, Erv) + ok |= ctxExpr + n.Left = typecheck(n.Left, ctxExpr) n.Left = defaultlit(n.Left, nil) n.Left = implicitstar(n.Left) l := n.Left - n.Right = typecheck(n.Right, Erv) + n.Right = typecheck(n.Right, ctxExpr) r := n.Right t := l.Type if t == nil || r.Type == nil { @@ -1098,8 +1098,8 @@ func typecheck1(n *Node, top int) (res *Node) { } case ORECV: - ok |= Etop | Erv - n.Left = typecheck(n.Left, Erv) + ok |= ctxStmt | ctxExpr + n.Left = typecheck(n.Left, ctxExpr) n.Left = defaultlit(n.Left, nil) l := n.Left t := l.Type @@ -1122,9 +1122,9 @@ func typecheck1(n *Node, top int) (res *Node) { n.Type = t.Elem() case OSEND: - ok |= Etop - n.Left = typecheck(n.Left, Erv) - n.Right = typecheck(n.Right, Erv) + ok |= ctxStmt + n.Left = typecheck(n.Left, ctxExpr) + n.Right = typecheck(n.Right, ctxExpr) n.Left = defaultlit(n.Left, nil) t := n.Left.Type if t == nil { @@ -1157,7 +1157,7 @@ func typecheck1(n *Node, top int) (res *Node) { // can construct an OSLICEHEADER node. // Components used in OSLICEHEADER that are supplied by parsed source code // have already been typechecked in e.g. OMAKESLICE earlier. - ok |= Erv + ok |= ctxExpr t := n.Type if t == nil { @@ -1176,9 +1176,9 @@ func typecheck1(n *Node, top int) (res *Node) { Fatalf("expected 2 params (len, cap) for OSLICEHEADER, got %d", x) } - n.Left = typecheck(n.Left, Erv) - l := typecheck(n.List.First(), Erv) - c := typecheck(n.List.Second(), Erv) + n.Left = typecheck(n.Left, ctxExpr) + l := typecheck(n.List.First(), ctxExpr) + c := typecheck(n.List.Second(), ctxExpr) l = defaultlit(l, types.Types[TINT]) c = defaultlit(c, types.Types[TINT]) @@ -1198,13 +1198,13 @@ func typecheck1(n *Node, top int) (res *Node) { n.List.SetSecond(c) case OSLICE, OSLICE3: - ok |= Erv - n.Left = typecheck(n.Left, Erv) + ok |= ctxExpr + n.Left = typecheck(n.Left, ctxExpr) low, high, max := n.SliceBounds() hasmax := n.Op.IsSlice3() - low = typecheck(low, Erv) - high = typecheck(high, Erv) - max = typecheck(max, Erv) + low = typecheck(low, ctxExpr) + high = typecheck(high, ctxExpr) + max = typecheck(max, ctxExpr) n.Left = defaultlit(n.Left, nil) low = indexlit(low) high = indexlit(high) @@ -1224,7 +1224,7 @@ func typecheck1(n *Node, top int) (res *Node) { n.Left = nod(OADDR, n.Left, nil) n.Left.SetImplicit(true) - n.Left = typecheck(n.Left, Erv) + n.Left = typecheck(n.Left, ctxExpr) l = n.Left } t := l.Type @@ -1273,7 +1273,7 @@ func typecheck1(n *Node, top int) (res *Node) { // call and call like case OCALL: - n.Left = typecheck(n.Left, Erv|Etype|Ecall) + n.Left = typecheck(n.Left, ctxExpr|Etype|ctxCallee) if n.Left.Diag() { n.SetDiag(true) } @@ -1281,7 +1281,7 @@ func typecheck1(n *Node, top int) (res *Node) { l := n.Left if l.Op == ONAME && l.SubOp() != 0 { - if n.Isddd() && l.SubOp() != OAPPEND { + if n.IsDDD() && l.SubOp() != OAPPEND { yyerror("invalid use of ... with builtin %v", l) } @@ -1296,7 +1296,7 @@ func typecheck1(n *Node, top int) (res *Node) { n.Left = defaultlit(n.Left, nil) l = n.Left if l.Op == OTYPE { - if n.Isddd() || l.Type.IsDDDArray() { + if n.IsDDD() || l.Type.IsDDDArray() { if !l.Type.Broke() { yyerror("invalid use of ... in type conversion to %v", l.Type) } @@ -1304,7 +1304,7 @@ func typecheck1(n *Node, top int) (res *Node) { } // pick off before type-checking arguments - ok |= Erv + ok |= ctxExpr // turn CALL(type, arg) into CONV(arg) w/ type n.Left = nil @@ -1319,10 +1319,10 @@ func typecheck1(n *Node, top int) (res *Node) { return n } - if n.List.Len() == 1 && !n.Isddd() { - n.List.SetFirst(typecheck(n.List.First(), Erv|Efnstruct)) + if n.List.Len() == 1 && !n.IsDDD() { + n.List.SetFirst(typecheck(n.List.First(), ctxExpr|ctxMultiOK)) } else { - typecheckslice(n.List.Slice(), Erv) + typecheckslice(n.List.Slice(), ctxExpr) } t := l.Type if t == nil { @@ -1365,12 +1365,12 @@ func typecheck1(n *Node, top int) (res *Node) { } } - typecheckaste(OCALL, n.Left, n.Isddd(), t.Params(), n.List, func() string { return fmt.Sprintf("argument to %v", n.Left) }) - ok |= Etop + typecheckaste(OCALL, n.Left, n.IsDDD(), t.Params(), n.List, func() string { return fmt.Sprintf("argument to %v", n.Left) }) + ok |= ctxStmt if t.NumResults() == 0 { break } - ok |= Erv + ok |= ctxExpr if t.NumResults() == 1 { n.Type = l.Type.Results().Field(0).Type @@ -1388,7 +1388,7 @@ func typecheck1(n *Node, top int) (res *Node) { } // multiple return - if top&(Efnstruct|Etop) == 0 { + if top&(ctxMultiOK|ctxStmt) == 0 { yyerror("multiple-value %v() in single-value context", l) break } @@ -1396,7 +1396,7 @@ func typecheck1(n *Node, top int) (res *Node) { n.Type = l.Type.Results() case OALIGNOF, OOFFSETOF, OSIZEOF: - ok |= Erv + ok |= ctxExpr if !onearg(n, "%v", n.Op) { n.Type = nil return n @@ -1407,13 +1407,13 @@ func typecheck1(n *Node, top int) (res *Node) { setintconst(n, evalunsafe(n)) case OCAP, OLEN: - ok |= Erv + ok |= ctxExpr if !onearg(n, "%v", n.Op) { n.Type = nil return n } - n.Left = typecheck(n.Left, Erv) + n.Left = typecheck(n.Left, ctxExpr) n.Left = defaultlit(n.Left, nil) n.Left = implicitstar(n.Left) l := n.Left @@ -1455,13 +1455,13 @@ func typecheck1(n *Node, top int) (res *Node) { } case OREAL, OIMAG: - ok |= Erv + ok |= ctxExpr if !onearg(n, "%v", n.Op) { n.Type = nil return n } - n.Left = typecheck(n.Left, Erv) + n.Left = typecheck(n.Left, ctxExpr) l := n.Left t := l.Type if t == nil { @@ -1516,11 +1516,11 @@ func typecheck1(n *Node, top int) (res *Node) { } case OCOMPLEX: - ok |= Erv + ok |= ctxExpr var r *Node var l *Node if n.List.Len() == 1 { - typecheckslice(n.List.Slice(), Efnstruct) + typecheckslice(n.List.Slice(), ctxMultiOK) if n.List.First().Op != OCALLFUNC && n.List.First().Op != OCALLMETH { yyerror("invalid operation: complex expects two arguments") n.Type = nil @@ -1546,8 +1546,8 @@ func typecheck1(n *Node, top int) (res *Node) { n.Type = nil return n } - n.Left = typecheck(n.Left, Erv) - n.Right = typecheck(n.Right, Erv) + n.Left = typecheck(n.Left, ctxExpr) + n.Right = typecheck(n.Right, ctxExpr) l = n.Left r = n.Right if l.Type == nil || r.Type == nil { @@ -1600,7 +1600,7 @@ func typecheck1(n *Node, top int) (res *Node) { n.Type = nil return n } - n.Left = typecheck(n.Left, Erv) + n.Left = typecheck(n.Left, ctxExpr) n.Left = defaultlit(n.Left, nil) l := n.Left t := l.Type @@ -1620,7 +1620,7 @@ func typecheck1(n *Node, top int) (res *Node) { return n } - ok |= Etop + ok |= ctxStmt case ODELETE: args := n.List @@ -1642,8 +1642,8 @@ func typecheck1(n *Node, top int) (res *Node) { return n } - ok |= Etop - typecheckslice(args.Slice(), Erv) + ok |= ctxStmt + typecheckslice(args.Slice(), ctxExpr) l := args.First() r := args.Second() if l.Type != nil && !l.Type.IsMap() { @@ -1655,7 +1655,7 @@ func typecheck1(n *Node, top int) (res *Node) { args.SetSecond(assignconv(r, l.Type.Key(), "delete")) case OAPPEND: - ok |= Erv + ok |= ctxExpr args := n.List if args.Len() == 0 { yyerror("missing arguments to append") @@ -1663,10 +1663,10 @@ func typecheck1(n *Node, top int) (res *Node) { return n } - if args.Len() == 1 && !n.Isddd() { - args.SetFirst(typecheck(args.First(), Erv|Efnstruct)) + if args.Len() == 1 && !n.IsDDD() { + args.SetFirst(typecheck(args.First(), ctxExpr|ctxMultiOK)) } else { - typecheckslice(args.Slice(), Erv) + typecheckslice(args.Slice(), ctxExpr) } t := args.First().Type @@ -1695,7 +1695,7 @@ func typecheck1(n *Node, top int) (res *Node) { return n } - if n.Isddd() { + if n.IsDDD() { if args.Len() == 1 { yyerror("cannot use ... on first argument to append") n.Type = nil @@ -1735,7 +1735,7 @@ func typecheck1(n *Node, top int) (res *Node) { } case OCOPY: - ok |= Etop | Erv + ok |= ctxStmt | ctxExpr args := n.List if args.Len() < 2 { yyerror("missing arguments to copy") @@ -1753,8 +1753,8 @@ func typecheck1(n *Node, top int) (res *Node) { n.Right = args.Second() n.List.Set(nil) n.Type = types.Types[TINT] - n.Left = typecheck(n.Left, Erv) - n.Right = typecheck(n.Right, Erv) + n.Left = typecheck(n.Left, ctxExpr) + n.Right = typecheck(n.Right, ctxExpr) if n.Left.Type == nil || n.Right.Type == nil { n.Type = nil return n @@ -1795,9 +1795,9 @@ func typecheck1(n *Node, top int) (res *Node) { } case OCONV: - ok |= Erv + ok |= ctxExpr checkwidth(n.Type) // ensure width is calculated for backend - n.Left = typecheck(n.Left, Erv) + n.Left = typecheck(n.Left, ctxExpr) n.Left = convlit1(n.Left, n.Type, true, noReuse) t := n.Left.Type if t == nil || n.Type == nil { @@ -1832,17 +1832,17 @@ func typecheck1(n *Node, top int) (res *Node) { // do not convert to []byte literal. See CL 125796. // generated code and compiler memory footprint is better without it. - case OSTRARRAYBYTE: + case OSTR2BYTES: break - case OSTRARRAYRUNE: + case OSTR2RUNES: if n.Left.Op == OLITERAL { n = stringtoruneslit(n) } } case OMAKE: - ok |= Erv + ok |= ctxExpr args := n.List.Slice() if len(args) == 0 { yyerror("missing argument to make") @@ -1875,12 +1875,12 @@ func typecheck1(n *Node, top int) (res *Node) { l = args[i] i++ - l = typecheck(l, Erv) + l = typecheck(l, ctxExpr) var r *Node if i < len(args) { r = args[i] i++ - r = typecheck(r, Erv) + r = typecheck(r, ctxExpr) } if l.Type == nil || (r != nil && r.Type == nil) { @@ -1905,7 +1905,7 @@ func typecheck1(n *Node, top int) (res *Node) { if i < len(args) { l = args[i] i++ - l = typecheck(l, Erv) + l = typecheck(l, ctxExpr) l = defaultlit(l, types.Types[TINT]) if l.Type == nil { n.Type = nil @@ -1926,7 +1926,7 @@ func typecheck1(n *Node, top int) (res *Node) { if i < len(args) { l = args[i] i++ - l = typecheck(l, Erv) + l = typecheck(l, ctxExpr) l = defaultlit(l, types.Types[TINT]) if l.Type == nil { n.Type = nil @@ -1953,7 +1953,7 @@ func typecheck1(n *Node, top int) (res *Node) { n.Type = t case ONEW: - ok |= Erv + ok |= ctxExpr args := n.List if args.Len() == 0 { yyerror("missing argument to new") @@ -1978,8 +1978,8 @@ func typecheck1(n *Node, top int) (res *Node) { n.Type = types.NewPtr(t) case OPRINT, OPRINTN: - ok |= Etop - typecheckslice(n.List.Slice(), Erv) + ok |= ctxStmt + typecheckslice(n.List.Slice(), ctxExpr) ls := n.List.Slice() for i1, n1 := range ls { // Special case for print: int constant is int64, not int. @@ -1991,12 +1991,12 @@ func typecheck1(n *Node, top int) (res *Node) { } case OPANIC: - ok |= Etop + ok |= ctxStmt if !onearg(n, "panic") { n.Type = nil return n } - n.Left = typecheck(n.Left, Erv) + n.Left = typecheck(n.Left, ctxExpr) n.Left = defaultlit(n.Left, types.Types[TINTER]) if n.Left.Type == nil { n.Type = nil @@ -2004,7 +2004,7 @@ func typecheck1(n *Node, top int) (res *Node) { } case ORECOVER: - ok |= Erv | Etop + ok |= ctxExpr | ctxStmt if n.List.Len() != 0 { yyerror("too many arguments to recover") n.Type = nil @@ -2014,15 +2014,15 @@ func typecheck1(n *Node, top int) (res *Node) { n.Type = types.Types[TINTER] case OCLOSURE: - ok |= Erv + ok |= ctxExpr typecheckclosure(n, top) if n.Type == nil { return n } case OITAB: - ok |= Erv - n.Left = typecheck(n.Left, Erv) + ok |= ctxExpr + n.Left = typecheck(n.Left, ctxExpr) t := n.Left.Type if t == nil { n.Type = nil @@ -2039,8 +2039,8 @@ func typecheck1(n *Node, top int) (res *Node) { Fatalf("cannot typecheck interface data %v", n) case OSPTR: - ok |= Erv - n.Left = typecheck(n.Left, Erv) + ok |= ctxExpr + n.Left = typecheck(n.Left, ctxExpr) t := n.Left.Type if t == nil { n.Type = nil @@ -2056,20 +2056,20 @@ func typecheck1(n *Node, top int) (res *Node) { } case OCLOSUREVAR: - ok |= Erv + ok |= ctxExpr case OCFUNC: - ok |= Erv - n.Left = typecheck(n.Left, Erv) + ok |= ctxExpr + n.Left = typecheck(n.Left, ctxExpr) n.Type = types.Types[TUINTPTR] case OCONVNOP: - ok |= Erv - n.Left = typecheck(n.Left, Erv) + ok |= ctxExpr + n.Left = typecheck(n.Left, ctxExpr) // statements case OAS: - ok |= Etop + ok |= ctxStmt typecheckas(n) @@ -2079,7 +2079,7 @@ func typecheck1(n *Node, top int) (res *Node) { } case OAS2: - ok |= Etop + ok |= ctxStmt typecheckas2(n) case OBREAK, @@ -2090,10 +2090,10 @@ func typecheck1(n *Node, top int) (res *Node) { OFALL, OVARKILL, OVARLIVE: - ok |= Etop + ok |= ctxStmt case OLABEL: - ok |= Etop + ok |= ctxStmt decldepth++ if n.Sym.IsBlank() { // Empty identifier is valid but useless. @@ -2104,22 +2104,22 @@ func typecheck1(n *Node, top int) (res *Node) { } case ODEFER: - ok |= Etop - n.Left = typecheck(n.Left, Etop|Erv) + ok |= ctxStmt + n.Left = typecheck(n.Left, ctxStmt|ctxExpr) if !n.Left.Diag() { checkdefergo(n) } - case OPROC: - ok |= Etop - n.Left = typecheck(n.Left, Etop|Erv) + case OGO: + ok |= ctxStmt + n.Left = typecheck(n.Left, ctxStmt|ctxExpr) checkdefergo(n) case OFOR, OFORUNTIL: - ok |= Etop - typecheckslice(n.Ninit.Slice(), Etop) + ok |= ctxStmt + typecheckslice(n.Ninit.Slice(), ctxStmt) decldepth++ - n.Left = typecheck(n.Left, Erv) + n.Left = typecheck(n.Left, ctxExpr) n.Left = defaultlit(n.Left, nil) if n.Left != nil { t := n.Left.Type @@ -2127,17 +2127,17 @@ func typecheck1(n *Node, top int) (res *Node) { yyerror("non-bool %L used as for condition", n.Left) } } - n.Right = typecheck(n.Right, Etop) + n.Right = typecheck(n.Right, ctxStmt) if n.Op == OFORUNTIL { - typecheckslice(n.List.Slice(), Etop) + typecheckslice(n.List.Slice(), ctxStmt) } - typecheckslice(n.Nbody.Slice(), Etop) + typecheckslice(n.Nbody.Slice(), ctxStmt) decldepth-- case OIF: - ok |= Etop - typecheckslice(n.Ninit.Slice(), Etop) - n.Left = typecheck(n.Left, Erv) + ok |= ctxStmt + typecheckslice(n.Ninit.Slice(), ctxStmt) + n.Left = typecheck(n.Left, ctxExpr) n.Left = defaultlit(n.Left, nil) if n.Left != nil { t := n.Left.Type @@ -2145,15 +2145,15 @@ func typecheck1(n *Node, top int) (res *Node) { yyerror("non-bool %L used as if condition", n.Left) } } - typecheckslice(n.Nbody.Slice(), Etop) - typecheckslice(n.Rlist.Slice(), Etop) + typecheckslice(n.Nbody.Slice(), ctxStmt) + typecheckslice(n.Rlist.Slice(), ctxStmt) case ORETURN: - ok |= Etop + ok |= ctxStmt if n.List.Len() == 1 { - typecheckslice(n.List.Slice(), Erv|Efnstruct) + typecheckslice(n.List.Slice(), ctxExpr|ctxMultiOK) } else { - typecheckslice(n.List.Slice(), Erv) + typecheckslice(n.List.Slice(), ctxExpr) } if Curfn == nil { yyerror("return outside function") @@ -2167,18 +2167,18 @@ func typecheck1(n *Node, top int) (res *Node) { typecheckaste(ORETURN, nil, false, Curfn.Type.Results(), n.List, func() string { return "return argument" }) case ORETJMP: - ok |= Etop + ok |= ctxStmt case OSELECT: - ok |= Etop + ok |= ctxStmt typecheckselect(n) case OSWITCH: - ok |= Etop + ok |= ctxStmt typecheckswitch(n) case ORANGE: - ok |= Etop + ok |= ctxStmt typecheckrange(n) case OTYPESW: @@ -2187,20 +2187,20 @@ func typecheck1(n *Node, top int) (res *Node) { return n case OXCASE: - ok |= Etop - typecheckslice(n.List.Slice(), Erv) - typecheckslice(n.Nbody.Slice(), Etop) + ok |= ctxStmt + typecheckslice(n.List.Slice(), ctxExpr) + typecheckslice(n.Nbody.Slice(), ctxStmt) case ODCLFUNC: - ok |= Etop + ok |= ctxStmt typecheckfunc(n) case ODCLCONST: - ok |= Etop - n.Left = typecheck(n.Left, Erv) + ok |= ctxStmt + n.Left = typecheck(n.Left, ctxExpr) case ODCLTYPE: - ok |= Etop + ok |= ctxStmt n.Left = typecheck(n.Left, Etype) checkwidth(n.Left.Type) if n.Left.Type != nil && n.Left.Type.NotInHeap() && n.Left.Name.Param.Pragma&NotInHeap == 0 { @@ -2232,20 +2232,20 @@ func typecheck1(n *Node, top int) (res *Node) { return n } - if top&(Erv|Etype) == Etype && n.Op != OTYPE { + if top&(ctxExpr|Etype) == Etype && n.Op != OTYPE { yyerror("%v is not a type", n) n.Type = nil return n } // TODO(rsc): simplify - if (top&(Ecall|Erv|Etype) != 0) && top&Etop == 0 && ok&(Erv|Etype|Ecall) == 0 { + if (top&(ctxCallee|ctxExpr|Etype) != 0) && top&ctxStmt == 0 && ok&(ctxExpr|Etype|ctxCallee) == 0 { yyerror("%v used as value", n) n.Type = nil return n } - if (top&Etop != 0) && top&(Ecall|Erv|Etype) == 0 && ok&Etop == 0 { + if (top&ctxStmt != 0) && top&(ctxCallee|ctxExpr|Etype) == 0 && ok&ctxStmt == 0 { if !n.Diag() { yyerror("%v evaluated but not used", n) n.SetDiag(true) @@ -2298,7 +2298,7 @@ func checksliceconst(lo *Node, hi *Node) bool { func checkdefergo(n *Node) { what := "defer" - if n.Op == OPROC { + if n.Op == OGO { what = "go" } @@ -2364,9 +2364,9 @@ func implicitstar(n *Node) *Node { if !t.IsArray() { return n } - n = nod(OIND, n, nil) + n = nod(ODEREF, n, nil) n.SetImplicit(true) - n = typecheck(n, Erv) + n = typecheck(n, ctxExpr) return n } @@ -2576,9 +2576,9 @@ func lookdot(n *Node, t *types.Type, dostrcmp int) *types.Field { } if t.IsInterface() { if n.Left.Type.IsPtr() { - n.Left = nod(OIND, n.Left, nil) // implicitstar + n.Left = nod(ODEREF, n.Left, nil) // implicitstar n.Left.SetImplicit(true) - n.Left = typecheck(n.Left, Erv) + n.Left = typecheck(n.Left, ctxExpr) } n.Op = ODOTINTER @@ -2600,11 +2600,11 @@ func lookdot(n *Node, t *types.Type, dostrcmp int) *types.Field { checklvalue(n.Left, "call pointer method on") n.Left = nod(OADDR, n.Left, nil) n.Left.SetImplicit(true) - n.Left = typecheck(n.Left, Etype|Erv) + n.Left = typecheck(n.Left, Etype|ctxExpr) } else if tt.IsPtr() && !rcvr.IsPtr() && types.Identical(tt.Elem(), rcvr) { - n.Left = nod(OIND, n.Left, nil) + n.Left = nod(ODEREF, n.Left, nil) n.Left.SetImplicit(true) - n.Left = typecheck(n.Left, Etype|Erv) + n.Left = typecheck(n.Left, Etype|ctxExpr) } else if tt.IsPtr() && tt.Elem().IsPtr() && types.Identical(derefall(tt), derefall(rcvr)) { yyerror("calling method %v with receiver %L requires explicit dereference", n.Sym, n.Left) for tt.IsPtr() { @@ -2612,9 +2612,9 @@ func lookdot(n *Node, t *types.Type, dostrcmp int) *types.Field { if rcvr.IsPtr() && !tt.Elem().IsPtr() { break } - n.Left = nod(OIND, n.Left, nil) + n.Left = nod(ODEREF, n.Left, nil) n.Left.SetImplicit(true) - n.Left = typecheck(n.Left, Etype|Erv) + n.Left = typecheck(n.Left, Etype|ctxExpr) tt = tt.Elem() } } else { @@ -2624,7 +2624,7 @@ func lookdot(n *Node, t *types.Type, dostrcmp int) *types.Field { pll := n ll := n.Left - for ll.Left != nil && (ll.Op == ODOT || ll.Op == ODOTPTR || ll.Op == OIND) { + for ll.Left != nil && (ll.Op == ODOT || ll.Op == ODOTPTR || ll.Op == ODEREF) { pll = ll ll = ll.Left } @@ -2657,7 +2657,7 @@ func nokeys(l Nodes) bool { func hasddd(t *types.Type) bool { for _, tl := range t.Fields().Slice() { - if tl.Isddd() { + if tl.IsDDD() { return true } } @@ -2698,7 +2698,7 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *types.Type, nl Nodes, rfs := n.Type.FieldSlice() var why string for i, tl := range lfs { - if tl.Isddd() { + if tl.IsDDD() { for _, tn := range rfs[i:] { if assignop(tn.Type, tl.Type.Elem(), &why) == 0 { if call != nil { @@ -2758,7 +2758,7 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *types.Type, nl Nodes, i = 0 for _, tl := range tstruct.Fields().Slice() { t = tl.Type - if tl.Isddd() { + if tl.IsDDD() { if isddd { if i >= nl.Len() { goto notenough @@ -3019,7 +3019,7 @@ func typecheckcomplit(n *Node) (res *Node) { norig := n.copy() setlineno(n.Right) - n.Right = typecheck(n.Right, Etype|Ecomplit) + n.Right = typecheck(n.Right, Etype|ctxCompLit) l := n.Right // sic t := l.Type if t == nil { @@ -3031,7 +3031,7 @@ func typecheckcomplit(n *Node) (res *Node) { if t.IsPtr() { // For better or worse, we don't allow pointers as the composite literal type, - // except when using the &T syntax, which sets implicit on the OIND. + // except when using the &T syntax, which sets implicit on the ODEREF. if !n.Right.Implicit() { yyerror("invalid pointer type %v for composite literal (use &%v instead)", t, t.Elem()) n.Type = nil @@ -3071,7 +3071,7 @@ func typecheckcomplit(n *Node) (res *Node) { setlineno(l) vp := &nl[i2] if l.Op == OKEY { - l.Left = typecheck(l.Left, Erv) + l.Left = typecheck(l.Left, ctxExpr) evconst(l.Left) i = nonnegintconst(l.Left) if i < 0 && !l.Left.Diag() { @@ -3092,7 +3092,7 @@ func typecheckcomplit(n *Node) (res *Node) { r := *vp pushtype(r, t.Elem()) - r = typecheck(r, Erv) + r = typecheck(r, ctxExpr) r = defaultlit(r, t.Elem()) *vp = assignconv(r, t.Elem(), "array or slice literal") @@ -3123,14 +3123,14 @@ func typecheckcomplit(n *Node) (res *Node) { for i3, l := range n.List.Slice() { setlineno(l) if l.Op != OKEY { - n.List.SetIndex(i3, typecheck(l, Erv)) + n.List.SetIndex(i3, typecheck(l, ctxExpr)) yyerror("missing key in map literal") continue } r := l.Left pushtype(r, t.Key()) - r = typecheck(r, Erv) + r = typecheck(r, ctxExpr) r = defaultlit(r, t.Key()) l.Left = assignconv(r, t.Key(), "map key") if l.Left.Op != OCONV { @@ -3139,7 +3139,7 @@ func typecheckcomplit(n *Node) (res *Node) { r = l.Right pushtype(r, t.Elem()) - r = typecheck(r, Erv) + r = typecheck(r, ctxExpr) r = defaultlit(r, t.Elem()) l.Right = assignconv(r, t.Elem(), "map value") } @@ -3157,7 +3157,7 @@ func typecheckcomplit(n *Node) (res *Node) { ls := n.List.Slice() for i, n1 := range ls { setlineno(n1) - n1 = typecheck(n1, Erv) + n1 = typecheck(n1, ctxExpr) ls[i] = n1 if i >= t.NumFields() { if !errored { @@ -3202,7 +3202,7 @@ func typecheckcomplit(n *Node) (res *Node) { // is never a valid struct literal key. if key.Sym == nil || key.Op == OXDOT || key.Sym.IsBlank() { yyerror("invalid field name %v in struct initializer", key) - l.Left = typecheck(l.Left, Erv) + l.Left = typecheck(l.Left, ctxExpr) continue } @@ -3224,7 +3224,7 @@ func typecheckcomplit(n *Node) (res *Node) { yyerror("mixture of field:value and value initializers") errored = true } - ls[i] = typecheck(ls[i], Erv) + ls[i] = typecheck(ls[i], ctxExpr) continue } @@ -3256,7 +3256,7 @@ func typecheckcomplit(n *Node) (res *Node) { l.Xoffset = f.Offset // No pushtype allowed here. Tried and rejected. - l.Left = typecheck(l.Left, Erv) + l.Left = typecheck(l.Left, ctxExpr) l.Left = assignconv(l.Left, f.Type, "field value") } } @@ -3298,7 +3298,7 @@ func islvalue(n *Node) bool { return false } fallthrough - case OIND, ODOTPTR, OCLOSUREVAR: + case ODEREF, ODOTPTR, OCLOSUREVAR: return true case ODOT: @@ -3392,8 +3392,8 @@ func samesafeexpr(l *Node, r *Node) bool { case ODOT, ODOTPTR: return l.Sym != nil && r.Sym != nil && l.Sym == r.Sym && samesafeexpr(l.Left, r.Left) - case OIND, OCONVNOP, - ONOT, OCOM, OPLUS, OMINUS: + case ODEREF, OCONVNOP, + ONOT, OBITNOT, OPLUS, ONEG: return samesafeexpr(l.Left, r.Left) case OCONV: @@ -3430,12 +3430,12 @@ func typecheckas(n *Node) { n.Left = resolve(n.Left) if n.Left.Name == nil || n.Left.Name.Defn != n || n.Left.Name.Param.Ntype != nil { - n.Left = typecheck(n.Left, Erv|Easgn) + n.Left = typecheck(n.Left, ctxExpr|ctxAssign) } - // Use Efnstruct so we can emit an "N variables but M values" error + // Use ctxMultiOK so we can emit an "N variables but M values" error // to be consistent with typecheckas2 (#26616). - n.Right = typecheck(n.Right, Erv|Efnstruct) + n.Right = typecheck(n.Right, ctxExpr|ctxMultiOK) checkassign(n, n.Left) if n.Right != nil && n.Right.Type != nil { if n.Right.Type.IsFuncArgStruct() { @@ -3459,7 +3459,7 @@ func typecheckas(n *Node) { n.SetTypecheck(1) if n.Left.Typecheck() == 0 { - n.Left = typecheck(n.Left, Erv|Easgn) + n.Left = typecheck(n.Left, ctxExpr|ctxAssign) } if !n.Left.isBlank() { checkwidth(n.Left.Type) // ensure width is calculated for backend @@ -3487,16 +3487,16 @@ func typecheckas2(n *Node) { ls[i1] = n1 if n1.Name == nil || n1.Name.Defn != n || n1.Name.Param.Ntype != nil { - ls[i1] = typecheck(ls[i1], Erv|Easgn) + ls[i1] = typecheck(ls[i1], ctxExpr|ctxAssign) } } cl := n.List.Len() cr := n.Rlist.Len() if cl > 1 && cr == 1 { - n.Rlist.SetFirst(typecheck(n.Rlist.First(), Erv|Efnstruct)) + n.Rlist.SetFirst(typecheck(n.Rlist.First(), ctxExpr|ctxMultiOK)) } else { - typecheckslice(n.Rlist.Slice(), Erv) + typecheckslice(n.Rlist.Slice(), ctxExpr) } checkassignlist(n, n.List) @@ -3601,7 +3601,7 @@ out: ls = n.List.Slice() for i1, n1 := range ls { if n1.Typecheck() == 0 { - ls[i1] = typecheck(ls[i1], Erv|Easgn) + ls[i1] = typecheck(ls[i1], ctxExpr|ctxAssign) } } } @@ -3618,7 +3618,7 @@ func typecheckfunc(n *Node) { } } - n.Func.Nname = typecheck(n.Func.Nname, Erv|Easgn) + n.Func.Nname = typecheck(n.Func.Nname, ctxExpr|ctxAssign) t := n.Func.Nname.Type if t == nil { return @@ -3658,7 +3658,7 @@ func stringtoruneslit(n *Node) *Node { nn := nod(OCOMPLIT, nil, typenod(n.Type)) nn.List.Set(l) - nn = typecheck(nn, Erv) + nn = typecheck(nn, ctxExpr) return nn } @@ -3810,7 +3810,7 @@ func typecheckdef(n *Node) { yyerrorl(n.Pos, "xxx") } - e = typecheck(e, Erv) + e = typecheck(e, ctxExpr) if Isconst(e, CTNIL) { yyerrorl(n.Pos, "const initializer cannot be nil") goto ret @@ -3872,12 +3872,12 @@ func typecheckdef(n *Node) { } if n.Name.Defn.Op == ONAME { - n.Name.Defn = typecheck(n.Name.Defn, Erv) + n.Name.Defn = typecheck(n.Name.Defn, ctxExpr) n.Type = n.Name.Defn.Type break } - n.Name.Defn = typecheck(n.Name.Defn, Etop) // fills in n.Type + n.Name.Defn = typecheck(n.Name.Defn, ctxStmt) // fills in n.Type case OTYPE: if p := n.Name.Param; p.Alias { diff --git a/src/cmd/compile/internal/gc/universe.go b/src/cmd/compile/internal/gc/universe.go index 760a8e40b0f5b3..745ce66bba2402 100644 --- a/src/cmd/compile/internal/gc/universe.go +++ b/src/cmd/compile/internal/gc/universe.go @@ -294,8 +294,8 @@ func typeinit() { okfor[ORSH] = okforand[:] // unary - okfor[OCOM] = okforand[:] - okfor[OMINUS] = okforarith[:] + okfor[OBITNOT] = okforand[:] + okfor[ONEG] = okforarith[:] okfor[ONOT] = okforbool[:] okfor[OPLUS] = okforarith[:] diff --git a/src/cmd/compile/internal/gc/unsafe.go b/src/cmd/compile/internal/gc/unsafe.go index 14ab33b0b6c9b4..2233961561230a 100644 --- a/src/cmd/compile/internal/gc/unsafe.go +++ b/src/cmd/compile/internal/gc/unsafe.go @@ -8,7 +8,7 @@ package gc func evalunsafe(n *Node) int64 { switch n.Op { case OALIGNOF, OSIZEOF: - n.Left = typecheck(n.Left, Erv) + n.Left = typecheck(n.Left, ctxExpr) n.Left = defaultlit(n.Left, nil) tr := n.Left.Type if tr == nil { @@ -30,10 +30,10 @@ func evalunsafe(n *Node) int64 { // Remember base of selector to find it back after dot insertion. // Since r->left may be mutated by typechecking, check it explicitly // first to track it correctly. - n.Left.Left = typecheck(n.Left.Left, Erv) + n.Left.Left = typecheck(n.Left.Left, ctxExpr) base := n.Left.Left - n.Left = typecheck(n.Left, Erv) + n.Left = typecheck(n.Left, ctxExpr) if n.Left.Type == nil { return 0 } diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index 5056212984ca8c..e3fd71e389938d 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -29,7 +29,7 @@ func walk(fn *Node) { // Final typecheck for any unused variables. for i, ln := range fn.Func.Dcl { if ln.Op == ONAME && (ln.Class() == PAUTO || ln.Class() == PAUTOHEAP) { - ln = typecheck(ln, Erv|Easgn) + ln = typecheck(ln, ctxExpr|ctxAssign) fn.Func.Dcl[i] = ln } } @@ -201,7 +201,7 @@ func walkstmt(n *Node) *Node { } nn := nod(OAS, v.Name.Param.Heapaddr, prealloc[v]) nn.SetColas(true) - nn = typecheck(nn, Etop) + nn = typecheck(nn, ctxStmt) return walkstmt(nn) } @@ -219,7 +219,7 @@ func walkstmt(n *Node) *Node { case ODEFER: Curfn.Func.SetHasDefer(true) fallthrough - case OPROC: + case OGO: switch n.Left.Op { case OPRINT, OPRINTN: n.Left = wrapCall(n.Left, &n.Ninit) @@ -274,7 +274,7 @@ func walkstmt(n *Node) *Node { } if cl == PPARAMOUT { if ln.isParamStackCopy() { - ln = walkexpr(typecheck(nod(OIND, ln.Name.Param.Heapaddr, nil), Erv), nil) + ln = walkexpr(typecheck(nod(ODEREF, ln.Name.Param.Heapaddr, nil), ctxExpr), nil) } rl = append(rl, ln) } @@ -461,8 +461,8 @@ func walkexpr(n *Node, init *Nodes) *Node { } if n.Op == ONAME && n.Class() == PAUTOHEAP { - nn := nod(OIND, n.Name.Param.Heapaddr, nil) - nn = typecheck(nn, Erv) + nn := nod(ODEREF, n.Name.Param.Heapaddr, nil) + nn = typecheck(nn, ctxExpr) nn = walkexpr(nn, init) nn.Left.SetNonNil(true) return nn @@ -482,8 +482,8 @@ opswitch: // If these return early, make sure to still call // stringsym for constant strings. - case ONOT, OMINUS, OPLUS, OCOM, OREAL, OIMAG, ODOTMETH, ODOTINTER, - OIND, OSPTR, OITAB, OIDATA, OADDR: + case ONOT, ONEG, OPLUS, OBITNOT, OREAL, OIMAG, ODOTMETH, ODOTINTER, + ODEREF, OSPTR, OITAB, OIDATA, OADDR: n.Left = walkexpr(n.Left, init) case OEFACE, OAND, OSUB, OMUL, OADD, OOR, OXOR, OLSH, ORSH: @@ -623,7 +623,7 @@ opswitch: if n.Op == OASOP { // Rewrite x op= y into x = x op y. n.Right = nod(n.SubOp(), n.Left, n.Right) - n.Right = typecheck(n.Right, Erv) + n.Right = typecheck(n.Right, ctxExpr) n.Op = OAS n.ResetAux() @@ -667,7 +667,7 @@ opswitch: case isAppendOfMake(r): // x = append(y, make([]T, y)...) r = extendslice(r, init) - case r.Isddd(): + case r.IsDDD(): r = appendslice(r, init) // also works for append(slice, string). default: r = walkappend(r, init, n) @@ -731,7 +731,7 @@ opswitch: ok := n.List.Second() call := mkcall1(fn, ok.Type, init, r.Left, n1) n = nod(OAS, ok, call) - n = typecheck(n, Etop) + n = typecheck(n, ctxStmt) // a,b = m[i] case OAS2MAPR: @@ -787,10 +787,10 @@ opswitch: n.List.SetFirst(var_) n = walkexpr(n, init) init.Append(n) - n = nod(OAS, a, nod(OIND, var_, nil)) + n = nod(OAS, a, nod(ODEREF, var_, nil)) } - n = typecheck(n, Etop) + n = typecheck(n, ctxStmt) n = walkexpr(n, init) case ODELETE: @@ -864,13 +864,13 @@ opswitch: case !fromType.IsInterface() && n.Esc == EscNone && fromType.Width <= 1024: // n.Left does not escape. Use a stack temporary initialized to n.Left. value = temp(fromType) - init.Append(typecheck(nod(OAS, value, n.Left), Etop)) + init.Append(typecheck(nod(OAS, value, n.Left), ctxStmt)) } if value != nil { // Value is identical to n.Left. // Construct the interface directly: {type/itab, &value}. - l := nod(OEFACE, typeword(), typecheck(nod(OADDR, value, nil), Erv)) + l := nod(OEFACE, typeword(), typecheck(nod(OADDR, value, nil), ctxExpr)) l.Type = toType l.SetTypecheck(n.Typecheck()) n = l @@ -890,10 +890,10 @@ opswitch: // Get the itab out of the interface. tmp := temp(types.NewPtr(types.Types[TUINT8])) - init.Append(nod(OAS, tmp, typecheck(nod(OITAB, c, nil), Erv))) + init.Append(nod(OAS, tmp, typecheck(nod(OITAB, c, nil), ctxExpr))) // Get the type out of the itab. - nif := nod(OIF, typecheck(nod(ONE, tmp, nodnil()), Erv), nil) + nif := nod(OIF, typecheck(nod(ONE, tmp, nodnil()), ctxExpr), nil) nif.Nbody.Set1(nod(OAS, tmp, itabType(tmp))) init.Append(nif) @@ -917,7 +917,7 @@ opswitch: dowidth(fn.Type) call := nod(OCALL, fn, nil) call.List.Set1(n.Left) - call = typecheck(call, Erv) + call = typecheck(call, ctxExpr) call = walkexpr(call, init) call = safeexpr(call, init) e := nod(OEFACE, typeword(), call) @@ -956,7 +956,7 @@ opswitch: dowidth(fn.Type) n = nod(OCALL, fn, nil) n.List.Set2(tab, v) - n = typecheck(n, Erv) + n = typecheck(n, ctxExpr) n = walkexpr(n, init) case OCONV, OCONVNOP: @@ -971,8 +971,8 @@ opswitch: case OANDNOT: n.Left = walkexpr(n.Left, init) n.Op = OAND - n.Right = nod(OCOM, n.Right, nil) - n.Right = typecheck(n.Right, Erv) + n.Right = nod(OBITNOT, n.Right, nil) + n.Right = typecheck(n.Right, ctxExpr) n.Right = walkexpr(n.Right, init) case ODIV, OMOD: @@ -1107,7 +1107,7 @@ opswitch: } n.Type = types.NewPtr(t.Elem()) n.SetNonNil(true) // mapaccess1* and mapassign always return non-nil pointers. - n = nod(OIND, n, nil) + n = nod(ODEREF, n, nil) n.Type = t.Elem() n.SetTypecheck(1) @@ -1151,10 +1151,10 @@ opswitch: } r := temp(n.Type.Elem()) r = nod(OAS, r, nil) // zero temp - r = typecheck(r, Etop) + r = typecheck(r, ctxStmt) init.Append(r) r = nod(OADDR, r.Left, nil) - r = typecheck(r, Erv) + r = typecheck(r, ctxExpr) n = r } else { n = callnew(n.Type.Elem()) @@ -1207,7 +1207,7 @@ opswitch: // var hv hmap hv := temp(hmapType) zero := nod(OAS, hv, nil) - zero = typecheck(zero, Etop) + zero = typecheck(zero, ctxStmt) init.Append(zero) // h = &hv h = nod(OADDR, hv, nil) @@ -1223,7 +1223,7 @@ opswitch: bv := temp(bmap(t)) zero = nod(OAS, bv, nil) - zero = typecheck(zero, Etop) + zero = typecheck(zero, ctxStmt) init.Append(zero) // b = &bv @@ -1232,7 +1232,7 @@ opswitch: // h.buckets = b bsym := hmapType.Field(5).Sym // hmap.buckets see reflect.go:hmap na := nod(OAS, nodSym(ODOT, h, bsym), b) - na = typecheck(na, Etop) + na = typecheck(na, ctxStmt) init.Append(na) } } @@ -1252,7 +1252,7 @@ opswitch: rand := mkcall("fastrand", types.Types[TUINT32], init) hashsym := hmapType.Field(4).Sym // hmap.hash0 see reflect.go:hmap a := nod(OAS, nodSym(ODOT, h, hashsym), rand) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) a = walkexpr(a, init) init.Append(a) n = convnop(h, t) @@ -1308,12 +1308,12 @@ opswitch: t = types.NewArray(t.Elem(), nonnegintconst(r)) // [r]T var_ := temp(t) a := nod(OAS, var_, nil) // zero temp - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) init.Append(a) r := nod(OSLICE, var_, nil) // arr[:l] r.SetSliceBounds(nil, l, nil) r = conv(r, n.Type) // in case n.Type is named. - r = typecheck(r, Erv) + r = typecheck(r, ctxExpr) r = walkexpr(r, init) n = r } else { @@ -1347,7 +1347,7 @@ opswitch: m.Left.SetNonNil(true) m.List.Set2(conv(len, types.Types[TINT]), conv(cap, types.Types[TINT])) - m = typecheck(m, Erv) + m = typecheck(m, ctxExpr) m = walkexpr(m, init) n = m } @@ -1363,7 +1363,7 @@ opswitch: // intstring(*[4]byte, rune) n = mkcall("intstring", n.Type, init, a, conv(n.Left, types.Types[TINT64])) - case OARRAYBYTESTR: + case OBYTES2STR: a := nodnil() if n.Esc == EscNone { // Create temporary buffer for string on stack. @@ -1376,11 +1376,11 @@ opswitch: n = mkcall("slicebytetostring", n.Type, init, a, n.Left) // slicebytetostringtmp([]byte) string; - case OARRAYBYTESTRTMP: + case OBYTES2STRTMP: n.Left = walkexpr(n.Left, init) if !instrumenting { - // Let the backend handle OARRAYBYTESTRTMP directly + // Let the backend handle OBYTES2STRTMP directly // to avoid a function call to slicebytetostringtmp. break } @@ -1388,7 +1388,7 @@ opswitch: n = mkcall("slicebytetostringtmp", n.Type, init, n.Left) // slicerunetostring(*[32]byte, []rune) string; - case OARRAYRUNESTR: + case ORUNES2STR: a := nodnil() if n.Esc == EscNone { @@ -1400,7 +1400,7 @@ opswitch: n = mkcall("slicerunetostring", n.Type, init, a, n.Left) - case OSTRARRAYBYTE: + case OSTR2BYTES: s := n.Left if Isconst(s, CTSTR) { sc := s.Val().U.(string) @@ -1414,14 +1414,14 @@ opswitch: a = callnew(t) } p := temp(t.PtrTo()) // *[n]byte - init.Append(typecheck(nod(OAS, p, a), Etop)) + init.Append(typecheck(nod(OAS, p, a), ctxStmt)) // Copy from the static string data to the [n]byte. if len(sc) > 0 { as := nod(OAS, - nod(OIND, p, nil), - nod(OIND, convnop(nod(OSPTR, s, nil), t.PtrTo()), nil)) - as = typecheck(as, Etop) + nod(ODEREF, p, nil), + nod(ODEREF, convnop(nod(OSPTR, s, nil), t.PtrTo()), nil)) + as = typecheck(as, ctxStmt) as = walkstmt(as) init.Append(as) } @@ -1444,7 +1444,7 @@ opswitch: // stringtoslicebyte(*32[byte], string) []byte; n = mkcall("stringtoslicebyte", n.Type, init, a, conv(s, types.Types[TSTRING])) - case OSTRARRAYBYTETMP: + case OSTR2BYTESTMP: // []byte(string) conversion that creates a slice // referring to the actual string bytes. // This conversion is handled later by the backend and @@ -1455,7 +1455,7 @@ opswitch: n.Left = walkexpr(n.Left, init) // stringtoslicerune(*[32]rune, string) []rune - case OSTRARRAYRUNE: + case OSTR2RUNES: a := nodnil() if n.Esc == EscNone { @@ -1475,7 +1475,7 @@ opswitch: vstat.Name.SetReadonly(true) fixedlit(inInitFunction, initKindStatic, n, vstat, init) n = vstat - n = typecheck(n, Erv) + n = typecheck(n, ctxExpr) break } var_ := temp(n.Type) @@ -1507,7 +1507,7 @@ opswitch: Fatalf("evconst changed Type: %v had type %v, now %v", n, t, n.Type) } if n.Op == OLITERAL { - n = typecheck(n, Erv) + n = typecheck(n, ctxExpr) // Emit string symbol now to avoid emitting // any concurrently during the backend. if s, ok := n.Val().U.(string); ok { @@ -1668,7 +1668,7 @@ func ascompatet(nl Nodes, nr *types.Type) []*Node { // deferred until all the returned values have been read. if fncall(l, r.Type) { tmp := temp(r.Type) - tmp = typecheck(tmp, Erv) + tmp = typecheck(tmp, ctxExpr) a := nod(OAS, l, tmp) a = convas(a, &mm) mm.Append(a) @@ -1733,7 +1733,7 @@ func mkdotargslice(typ *types.Type, args []*Node, init *Nodes, ddd *Node) *Node } n.List.Set(args) n.Esc = esc - n = typecheck(n, Erv) + n = typecheck(n, ctxExpr) if n.Type == nil { Fatalf("mkdotargslice: typecheck failed") } @@ -1754,7 +1754,7 @@ func walkCall(n *Node, init *Nodes) { // parameter) and this is not a ... call expression, // then assign the remaining arguments as a slice. if nf := params.NumFields(); nf > 0 { - if last := params.Field(nf - 1); last.Isddd() && !n.Isddd() { + if last := params.Field(nf - 1); last.IsDDD() && !n.IsDDD() { tail := args[nf-1:] slice := mkdotargslice(last.Type, tail, init, n.Right) // Allow immediate GC. @@ -1930,11 +1930,11 @@ func walkprint(nn *Node, init *Nodes) *Node { calls = append(calls, mkcall("printunlock", nil, init)) - typecheckslice(calls, Etop) + typecheckslice(calls, ctxStmt) walkexprlist(calls, init) r := nod(OEMPTY, nil, nil) - r = typecheck(r, Etop) + r = typecheck(r, ctxStmt) r = walkexpr(r, init) r.Ninit.Set(calls) return r @@ -2054,7 +2054,7 @@ func reorder3(all []*Node) []*Node { all[i] = convas(all[i], &mapinit) } - case OIND, ODOTPTR: + case ODEREF, ODOTPTR: l.Left = reorder3save(l.Left, all, i, &early) } @@ -2079,7 +2079,7 @@ func reorder3save(n *Node, all []*Node, i int, early *[]*Node) *Node { q := temp(n.Type) q = nod(OAS, q, n) - q = typecheck(q, Etop) + q = typecheck(q, ctxStmt) *early = append(*early, q) return q.Left } @@ -2210,8 +2210,8 @@ func varexpr(n *Node) bool { OAND, OANDNOT, OPLUS, - OMINUS, - OCOM, + ONEG, + OBITNOT, OPAREN, OANDAND, OOROR, @@ -2315,7 +2315,7 @@ func paramstoheap(params *types.Type) []*Node { if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil { nn = append(nn, walkstmt(nod(ODCL, v, nil))) if stackcopy.Class() == PPARAM { - nn = append(nn, walkstmt(typecheck(nod(OAS, v, stackcopy), Etop))) + nn = append(nn, walkstmt(typecheck(nod(OAS, v, stackcopy), ctxStmt))) } } } @@ -2363,7 +2363,7 @@ func returnsfromheap(params *types.Type) []*Node { continue } if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil && stackcopy.Class() == PPARAMOUT { - nn = append(nn, walkstmt(typecheck(nod(OAS, stackcopy, v), Etop))) + nn = append(nn, walkstmt(typecheck(nod(OAS, stackcopy, v), ctxStmt))) } } @@ -2398,9 +2398,9 @@ func vmkcall(fn *Node, t *types.Type, init *Nodes, va []*Node) *Node { r := nod(OCALL, fn, nil) r.List.Set(va) if fn.Type.NumResults() > 0 { - r = typecheck(r, Erv|Efnstruct) + r = typecheck(r, ctxExpr|ctxMultiOK) } else { - r = typecheck(r, Etop) + r = typecheck(r, ctxStmt) } r = walkexpr(r, init) r.Type = t @@ -2421,16 +2421,16 @@ func conv(n *Node, t *types.Type) *Node { } n = nod(OCONV, n, nil) n.Type = t - n = typecheck(n, Erv) + n = typecheck(n, ctxExpr) return n } // convnop converts node n to type t using the OCONVNOP op -// and typechecks the result with Erv. +// and typechecks the result with ctxExpr. func convnop(n *Node, t *types.Type) *Node { n = nod(OCONVNOP, n, nil) n.Type = t - n = typecheck(n, Erv) + n = typecheck(n, ctxExpr) return n } @@ -2591,7 +2591,7 @@ func addstr(n *Node, init *Nodes) *Node { cat := syslook(fn) r := nod(OCALL, cat, nil) r.List.Set(args) - r = typecheck(r, Erv) + r = typecheck(r, ctxExpr) r = walkexpr(r, init) r.Type = n.Type @@ -2715,7 +2715,7 @@ func appendslice(n *Node, init *Nodes) *Node { } ln := append(nodes.Slice(), ncopy) - typecheckslice(ln, Etop) + typecheckslice(ln, ctxStmt) walkstmtlist(ln) init.Append(ln...) return s @@ -2732,7 +2732,7 @@ func isAppendOfMake(n *Node) bool { Fatalf("missing typecheck: %+v", n) } - if n.Op != OAPPEND || !n.Isddd() || n.List.Len() != 2 { + if n.Op != OAPPEND || !n.IsDDD() || n.List.Len() != 2 { return false } @@ -2785,7 +2785,7 @@ func isAppendOfMake(n *Node) bool { func extendslice(n *Node, init *Nodes) *Node { // isAppendOfMake made sure l2 fits in an int. l2 := conv(n.List.Second().Left, types.Types[TINT]) - l2 = typecheck(l2, Erv) + l2 = typecheck(l2, ctxExpr) n.List.SetSecond(l2) // walkAppendArgs expects l2 in n.List.Second(). walkAppendArgs(n, init) @@ -2871,7 +2871,7 @@ func extendslice(n *Node, init *Nodes) *Node { nodes = append(nodes, clr.Slice()...) } - typecheckslice(nodes, Etop) + typecheckslice(nodes, ctxStmt) walkstmtlist(nodes) init.Append(nodes...) return s @@ -2970,7 +2970,7 @@ func walkappend(n *Node, init *Nodes, dst *Node) *Node { } } - typecheckslice(l, Etop) + typecheckslice(l, ctxStmt) walkstmtlist(l) init.Append(l...) return ns @@ -3043,7 +3043,7 @@ func copyany(n *Node, init *Nodes, runtimecall bool) *Node { call := mkcall1(fn, nil, init, nto, nfrm, nwid) ne.Nbody.Append(call) - typecheckslice(l, Etop) + typecheckslice(l, ctxStmt) walkstmtlist(l) init.Append(l...) return nlen @@ -3189,12 +3189,12 @@ func walkcompare(n *Node, init *Nodes) *Node { // eq algs take pointers pl := temp(types.NewPtr(t)) al := nod(OAS, pl, nod(OADDR, cmpl, nil)) - al = typecheck(al, Etop) + al = typecheck(al, ctxStmt) init.Append(al) pr := temp(types.NewPtr(t)) ar := nod(OAS, pr, nod(OADDR, cmpr, nil)) - ar = typecheck(ar, Etop) + ar = typecheck(ar, ctxStmt) init.Append(ar) fn, needsize := eqfor(t) @@ -3301,9 +3301,9 @@ func walkcompare(n *Node, init *Nodes) *Node { // an expression which might panic. See issue 23837. t := temp(cmpl.Type) a1 := nod(OAS, t, cmpl) - a1 = typecheck(a1, Etop) + a1 = typecheck(a1, ctxStmt) a2 := nod(OAS, t, cmpr) - a2 = typecheck(a2, Etop) + a2 = typecheck(a2, ctxStmt) init.Append(a1, a2) } n = finishcompare(n, expr, init) @@ -3490,7 +3490,7 @@ func walkcompareString(n *Node, init *Nodes) *Node { // The result of finishcompare MUST be assigned back to n, e.g. // n.Left = finishcompare(n.Left, x, r, init) func finishcompare(n, r *Node, init *Nodes) *Node { - r = typecheck(r, Erv) + r = typecheck(r, ctxExpr) r = conv(r, n.Type) r = walkexpr(r, init) return r @@ -3626,7 +3626,7 @@ func walkinrange(n *Node, init *Nodes) *Node { cmp = addinit(cmp, l.Ninit.Slice()) cmp = addinit(cmp, r.Ninit.Slice()) // Typecheck the AST rooted at cmp... - cmp = typecheck(cmp, Erv) + cmp = typecheck(cmp, ctxExpr) // ...but then reset cmp's type to match n's type. cmp.Type = n.Type cmp = walkexpr(cmp, init) @@ -3816,10 +3816,10 @@ func candiscard(n *Node) bool { OADDSTR, OADDR, OANDAND, - OARRAYBYTESTR, - OARRAYRUNESTR, - OSTRARRAYBYTE, - OSTRARRAYRUNE, + OBYTES2STR, + ORUNES2STR, + OSTR2BYTES, + OSTR2RUNES, OCAP, OCOMPLIT, OMAPLIT, @@ -3847,9 +3847,9 @@ func candiscard(n *Node) bool { OANDNOT, ONEW, ONOT, - OCOM, + OBITNOT, OPLUS, - OMINUS, + ONEG, OOROR, OPAREN, ORUNESTR, @@ -3917,19 +3917,19 @@ func wrapCall(n *Node, init *Nodes) *Node { a := nod(n.Op, nil, nil) a.List.Set(paramNnames(t.Type)) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) fn.Nbody.Set1(a) funcbody() - fn = typecheck(fn, Etop) - typecheckslice(fn.Nbody.Slice(), Etop) + fn = typecheck(fn, ctxStmt) + typecheckslice(fn.Nbody.Slice(), ctxStmt) xtop = append(xtop, fn) a = nod(OCALL, nil, nil) a.Left = fn.Func.Nname a.List.Set(n.List.Slice()) - a = typecheck(a, Etop) + a = typecheck(a, ctxStmt) a = walkexpr(a, init) return a } @@ -3970,5 +3970,5 @@ func canMergeLoads() bool { // isRuneCount reports whether n is of the form len([]rune(string)). // These are optimized into a call to runtime.countrunes. func isRuneCount(n *Node) bool { - return Debug['N'] == 0 && !instrumenting && n.Op == OLEN && n.Left.Op == OSTRARRAYRUNE + return Debug['N'] == 0 && !instrumenting && n.Op == OLEN && n.Left.Op == OSTR2RUNES } diff --git a/src/cmd/compile/internal/types/identity.go b/src/cmd/compile/internal/types/identity.go index 21524852579833..7c14a03ba16dd6 100644 --- a/src/cmd/compile/internal/types/identity.go +++ b/src/cmd/compile/internal/types/identity.go @@ -92,7 +92,7 @@ func identical(t1, t2 *Type, cmpTags bool, assumedEqual map[typePair]struct{}) b } for i, f1 := range fs1 { f2 := fs2[i] - if f1.Isddd() != f2.Isddd() || !identical(f1.Type, f2.Type, cmpTags, assumedEqual) { + if f1.IsDDD() != f2.IsDDD() || !identical(f1.Type, f2.Type, cmpTags, assumedEqual) { return false } } diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go index 45355e5798ce35..46a9b816809b55 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -374,16 +374,16 @@ type Field struct { } const ( - fieldIsddd = 1 << iota // field is ... argument + fieldIsDDD = 1 << iota // field is ... argument fieldBroke // broken field definition fieldNointerface ) -func (f *Field) Isddd() bool { return f.flags&fieldIsddd != 0 } +func (f *Field) IsDDD() bool { return f.flags&fieldIsDDD != 0 } func (f *Field) Broke() bool { return f.flags&fieldBroke != 0 } func (f *Field) Nointerface() bool { return f.flags&fieldNointerface != 0 } -func (f *Field) SetIsddd(b bool) { f.flags.set(fieldIsddd, b) } +func (f *Field) SetIsDDD(b bool) { f.flags.set(fieldIsDDD, b) } func (f *Field) SetBroke(b bool) { f.flags.set(fieldBroke, b) } func (f *Field) SetNointerface(b bool) { f.flags.set(fieldNointerface, b) } @@ -743,7 +743,7 @@ func (t *Type) NumResults() int { return t.FuncType().Results.NumFields() } // IsVariadic reports whether function type t is variadic. func (t *Type) IsVariadic() bool { n := t.NumParams() - return n > 0 && t.Params().Field(n-1).Isddd() + return n > 0 && t.Params().Field(n-1).IsDDD() } // Recv returns the receiver of function type t, if any. @@ -1163,8 +1163,8 @@ func (t *Type) cmp(x *Type) Cmp { for i := 0; i < len(tfs) && i < len(xfs); i++ { ta := tfs[i] tb := xfs[i] - if ta.Isddd() != tb.Isddd() { - return cmpForNe(!ta.Isddd()) + if ta.IsDDD() != tb.IsDDD() { + return cmpForNe(!ta.IsDDD()) } if c := ta.Type.cmp(tb.Type); c != CMPeq { return c diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index a94a43fd664593..8d7b14d17c6502 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -804,7 +804,7 @@ func runInstall(dir string, ch chan struct{}) { if len(sfiles) > 0 { symabis = pathf("%s/symabis", workdir) var wg sync.WaitGroup - asmabis := append(asmArgs[:len(asmArgs):len(asmArgs)], "-symabis", "-o", symabis) + asmabis := append(asmArgs[:len(asmArgs):len(asmArgs)], "-gensymabis", "-o", symabis) asmabis = append(asmabis, sfiles...) if err := ioutil.WriteFile(goasmh, nil, 0666); err != nil { fatalf("cannot write empty go_asm.h: %s", err) diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index e7412f9bc7c515..12134b21c02be8 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -1299,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'. diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 3d1b0e649d7f19..ae738c6a12e526 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -1343,6 +1343,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) } diff --git a/src/cmd/go/internal/modfetch/cache.go b/src/cmd/go/internal/modfetch/cache.go index 1f9cc96c3ec808..171718d20b0689 100644 --- a/src/cmd/go/internal/modfetch/cache.go +++ b/src/cmd/go/internal/modfetch/cache.go @@ -129,16 +129,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) diff --git a/src/cmd/go/internal/modfetch/fetch.go b/src/cmd/go/internal/modfetch/fetch.go index 8485932b42fca5..9984595c05510f 100644 --- a/src/cmd/go/internal/modfetch/fetch.go +++ b/src/cmd/go/internal/modfetch/fetch.go @@ -119,11 +119,11 @@ func downloadZip(mod module.Version, target string) error { if err != nil { return err } - prefix := mod.Path + "@" + mod.Version + 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, f.Name) + return fmt.Errorf("zip for %s has unexpected file %s", prefix[:len(prefix)-1], f.Name) } } z.Close() diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go index ffc9a12f953643..c2e134c2d695dc 100644 --- a/src/cmd/go/internal/modget/get.go +++ b/src/cmd/go/internal/modget/get.go @@ -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/src/cmd/go/internal/semver/semver.go b/src/cmd/go/internal/semver/semver.go index 4af7118e55d2ef..122e612dd4b8f0 100644 --- a/src/cmd/go/internal/semver/semver.go +++ b/src/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/src/cmd/go/internal/semver/semver_test.go b/src/cmd/go/internal/semver/semver_test.go index 96b64a58075498..77025a44abd60a 100644 --- a/src/cmd/go/internal/semver/semver_test.go +++ b/src/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/src/cmd/go/internal/vet/vet.go b/src/cmd/go/internal/vet/vet.go index 616f774bf64592..327b761c3cd6bf 100644 --- a/src/cmd/go/internal/vet/vet.go +++ b/src/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(cmd.Usage, args) + vetFlags, pkgArgs := vetFlags(vetUsage, args) work.BuildInit() work.VetFlags = vetFlags diff --git a/src/cmd/go/internal/vet/vetflag.go b/src/cmd/go/internal/vet/vetflag.go index 9b5184a4d4ef89..37342f41633420 100644 --- a/src/cmd/go/internal/vet/vetflag.go +++ b/src/cmd/go/internal/vet/vetflag.go @@ -166,3 +166,21 @@ func vetFlags(usage func(), 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/src/cmd/go/internal/work/buildid.go b/src/cmd/go/internal/work/buildid.go index c5aa1db50b8d60..750bc3c6cdbe45 100644 --- a/src/cmd/go/internal/work/buildid.go +++ b/src/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 @@ -208,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() diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index d6f9021c35c090..ca588911fed84d 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -881,6 +881,7 @@ func (b *Builder) loadCachedSrcFiles(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") @@ -914,6 +915,7 @@ func buildVetConfig(a *Action, srcfiles []string) { // 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), diff --git a/src/cmd/go/internal/work/gc.go b/src/cmd/go/internal/work/gc.go index 89ef2da8cb59f3..a14a970ffbd3c3 100644 --- a/src/cmd/go/internal/work/gc.go +++ b/src/cmd/go/internal/work/gc.go @@ -265,7 +265,7 @@ func (gcToolchain) asm(b *Builder, a *Action, sfiles []string) ([]string, error) 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, "-symabis", "-o", path) + args = append(args, "-gensymabis", "-o", path) for _, sfile := range sfiles { if p.ImportPath == "runtime/cgo" && strings.HasPrefix(sfile, "gcc_") { continue @@ -274,7 +274,7 @@ func (gcToolchain) symabis(b *Builder, a *Action, sfiles []string) (string, erro } // Supply an empty go_asm.h as if the compiler had been run. - // -symabis parsing is lax enough that we don't need the + // -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 diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go index 6a188262cce675..4f8ab7f55a9ebc 100644 --- a/src/cmd/go/main.go +++ b/src/cmd/go/main.go @@ -151,10 +151,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": diff --git a/src/cmd/go/proxy_test.go b/src/cmd/go/proxy_test.go index 97fc4b0e80735c..830cea029b7ac2 100644 --- a/src/cmd/go/proxy_test.go +++ b/src/cmd/go/proxy_test.go @@ -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} } diff --git a/src/cmd/go/testdata/mod/rsc.io_badzip_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_badzip_v1.0.0.txt new file mode 100644 index 00000000000000..07a38fa6d7d749 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_badzip_v1.0.0.txt @@ -0,0 +1,11 @@ +rsc.io/badzip v1.0.0 +written by hand + +-- .mod -- +module rsc.io/badzip +-- .info -- +{"Version":"v1.0.0"} +-- x.go -- +package x +-- /rsc.io/badzip@v1.0.0.txt -- +This file should not be here. diff --git a/src/cmd/go/testdata/script/help.txt b/src/cmd/go/testdata/script/help.txt index 3d0650880e603d..9f455256f72d88 100644 --- a/src/cmd/go/testdata/script/help.txt +++ b/src/cmd/go/testdata/script/help.txt @@ -34,6 +34,7 @@ stderr 'Run ''go help mod'' for usage.' ! 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. diff --git a/src/cmd/go/testdata/script/mod_download_hash.txt b/src/cmd/go/testdata/script/mod_download_hash.txt new file mode 100644 index 00000000000000..1662043207ed64 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_download_hash.txt @@ -0,0 +1,23 @@ +env GO111MODULE=on + +# Testing mod download with non semantic versions; turn off proxy. +[!net] skip +[!exec:git] skip +env GOPROXY= + +go mod download rsc.io/quote@a91498bed0a73d4bb9c1fb2597925f7883bc40a7 +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v0.0.0-20180709162918-a91498bed0a7.info +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v0.0.0-20180709162918-a91498bed0a7.mod +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v0.0.0-20180709162918-a91498bed0a7.zip + +go mod download rsc.io/quote@master +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v0.0.0-20180710144737-5d9f230bcfba.info +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v0.0.0-20180710144737-5d9f230bcfba.mod +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v0.0.0-20180710144737-5d9f230bcfba.zip + + +-- go.mod -- +module m + +-- m.go -- +package m \ No newline at end of file diff --git a/src/cmd/go/testdata/script/mod_load_badzip.txt b/src/cmd/go/testdata/script/mod_load_badzip.txt new file mode 100644 index 00000000000000..95513de4a65889 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_load_badzip.txt @@ -0,0 +1,11 @@ +# Zip files with unexpected file names inside should be rejected. +env GO111MODULE=on + +! go get -d rsc.io/badzip +stderr 'zip for rsc.io/badzip@v1.0.0 has unexpected file rsc.io/badzip@v1.0.0.txt' + +! go build rsc.io/badzip +stderr 'zip for rsc.io/badzip@v1.0.0 has unexpected file rsc.io/badzip@v1.0.0.txt' + +-- go.mod -- +module m diff --git a/src/cmd/go/testdata/script/vet_asm.txt b/src/cmd/go/testdata/script/vet_asm.txt index b7e1874b8cb0dd..807e2b76f58999 100644 --- a/src/cmd/go/testdata/script/vet_asm.txt +++ b/src/cmd/go/testdata/script/vet_asm.txt @@ -5,6 +5,21 @@ env GOARCH=amd64 ! go vet -asmdecl a stderr 'f: invalid MOVW of x' +# -c flag shows context +! go vet -c=2 -asmdecl a +stderr '...invalid MOVW...' +stderr '1 .*TEXT' +stderr '2 MOVW' +stderr '3 RET' +stderr '4' + +# -json causes success, even with diagnostics and errors. +go vet -json -asmdecl a +stderr '"a": {' +stderr '"asmdecl":' +stderr '"posn": ".*asm.s:2:1",' +stderr '"message": ".*invalid MOVW.*"' + -- a/a.go -- package a diff --git a/src/cmd/internal/objabi/flag.go b/src/cmd/internal/objabi/flag.go index 30cd7dccac20fb..90e944656bb8a2 100644 --- a/src/cmd/internal/objabi/flag.go +++ b/src/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/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index d10f4ab3c3ca14..a150306df9174d 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -1219,11 +1219,14 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) { pciterinit(ctxt, &pcfile, &s.FuncInfo.Pcfile) pciterinit(ctxt, &pcline, &s.FuncInfo.Pcline) - pciterinit(ctxt, &pcstmt, &sym.Pcdata{P: s.FuncInfo.IsStmtSym.P}) - if pcstmt.done != 0 { + isStmtSym := dwarfFuncSym(ctxt, s, dwarf.IsStmtPrefix, false) + if isStmtSym != nil && len(isStmtSym.P) > 0 { + pciterinit(ctxt, &pcstmt, &sym.Pcdata{P: isStmtSym.P}) + } else { // Assembly files lack a pcstmt section, we assume that every instruction // is a valid statement. + pcstmt.done = 1 pcstmt.value = 1 } diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go index 3eb3d058824f79..ba098611c084e4 100644 --- a/src/cmd/link/internal/ld/pcln.go +++ b/src/cmd/link/internal/ld/pcln.go @@ -520,10 +520,8 @@ func (ctxt *Link) findfunctab() { // find min and max address min := ctxt.Textp[0].Value - max := int64(0) - for _, s := range ctxt.Textp { - max = s.Value + s.Size - } + lastp := ctxt.Textp[len(ctxt.Textp)-1] + max := lastp.Value + lastp.Size // for each subbucket, compute the minimum of all symbol indexes // that map to that subbucket. diff --git a/src/cmd/link/internal/objfile/objfile.go b/src/cmd/link/internal/objfile/objfile.go index 77c3a7f9148c40..a85ba1ebee95be 100644 --- a/src/cmd/link/internal/objfile/objfile.go +++ b/src/cmd/link/internal/objfile/objfile.go @@ -320,8 +320,6 @@ overwrite: pc.InlTree[i].Func = r.readSymIndex() } - s.FuncInfo.IsStmtSym = r.syms.Lookup(dwarf.IsStmtPrefix+s.Name, int(s.Version)) - if !dupok { if s.Attr.OnList() { log.Fatalf("symbol %s listed multiple times", s.Name) diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go index 11a7aa2164311f..2ec5a2b18b10f0 100644 --- a/src/cmd/link/internal/ppc64/asm.go +++ b/src/cmd/link/internal/ppc64/asm.go @@ -374,6 +374,13 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { } func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool { + // Beware that bit0~bit15 start from the third byte of a instruction in Big-Endian machines. + if r.Type == objabi.R_ADDR || r.Type == objabi.R_POWER_TLS || r.Type == objabi.R_CALLPOWER { + } else { + if ctxt.Arch.ByteOrder == binary.BigEndian { + sectoff += 2 + } + } ctxt.Out.Write64(uint64(sectoff)) elfsym := r.Xsym.ElfsymForReloc() diff --git a/src/cmd/link/internal/ppc64/obj.go b/src/cmd/link/internal/ppc64/obj.go index e630f8c062b6be..fbedc728d9baea 100644 --- a/src/cmd/link/internal/ppc64/obj.go +++ b/src/cmd/link/internal/ppc64/obj.go @@ -93,9 +93,6 @@ func archinit(ctxt *ld.Link) { } case objabi.Hlinux: /* ppc64 elf */ - if ctxt.Arch == sys.ArchPPC64 { - *ld.FlagD = true // TODO(austin): ELF ABI v1 not supported yet - } ld.Elfinit(ctxt) ld.HEADR = ld.ELFRESERVE if *ld.FlagTextAddr == -1 { diff --git a/src/cmd/link/internal/sym/symbol.go b/src/cmd/link/internal/sym/symbol.go index 5e5fca467da2e8..a1af4670a28b55 100644 --- a/src/cmd/link/internal/sym/symbol.go +++ b/src/cmd/link/internal/sym/symbol.go @@ -499,7 +499,6 @@ type FuncInfo struct { Pcline Pcdata Pcinline Pcdata Pcdata []Pcdata - IsStmtSym *Symbol Funcdata []*Symbol Funcdataoff []int64 File []*Symbol diff --git a/src/cmd/vendor/README b/src/cmd/vendor/README index 740905c652fdb0..7eb97a1b9b16f6 100644 --- a/src/cmd/vendor/README +++ b/src/cmd/vendor/README @@ -19,3 +19,7 @@ make govendor work and will create the .cache folder in $GOROOT as a side-effect. Please make sure to delete the directory and not to include the directory in the commit by accident. + +The vendored copy of golang.org/x/tools is maintained by +running the update-xtools.sh script in this directory, +not by govendor. \ No newline at end of file diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/cmd/vet-lite/main.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/cmd/vet-lite/main.go deleted file mode 100644 index ae66a7df28decf..00000000000000 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/cmd/vet-lite/main.go +++ /dev/null @@ -1,83 +0,0 @@ -// The vet-lite command is a driver for static checkers conforming to -// the golang.org/x/tools/go/analysis API. It must be run by go vet: -// -// $ GOVETTOOL=$(which vet-lite) go vet -// -// For a checker also capable of running standalone, use multichecker. -package main - -import ( - "flag" - "log" - "strings" - - "golang.org/x/tools/go/analysis" - "golang.org/x/tools/go/analysis/internal/analysisflags" - "golang.org/x/tools/go/analysis/internal/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/pkgfact" - "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/unreachable" - "golang.org/x/tools/go/analysis/passes/unsafeptr" - "golang.org/x/tools/go/analysis/passes/unusedresult" -) - -var analyzers = []*analysis.Analyzer{ - // For now, just the traditional vet suite: - asmdecl.Analyzer, - assign.Analyzer, - atomic.Analyzer, - bools.Analyzer, - buildtag.Analyzer, - cgocall.Analyzer, - composite.Analyzer, - copylock.Analyzer, - httpresponse.Analyzer, - loopclosure.Analyzer, - lostcancel.Analyzer, - nilfunc.Analyzer, - pkgfact.Analyzer, - printf.Analyzer, - // shadow.Analyzer, // experimental; not enabled by default - shift.Analyzer, - stdmethods.Analyzer, - structtag.Analyzer, - tests.Analyzer, - unreachable.Analyzer, - unsafeptr.Analyzer, - unusedresult.Analyzer, -} - -func main() { - log.SetFlags(0) - log.SetPrefix("vet: ") - - if err := analysis.Validate(analyzers); err != nil { - log.Fatal(err) - } - - analyzers = analysisflags.Parse(analyzers, true) - - args := flag.Args() - if len(args) != 1 || !strings.HasSuffix(args[0], ".cfg") { - log.Fatalf("invalid command: want .cfg file (this reduced version of vet is intended to be run only by the 'go vet' command)") - } - - unitchecker.Main(args[0], analyzers) -} diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/doc.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/doc.go index 4223ab80fc1997..5dee615181b89a 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/doc.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/doc.go @@ -72,11 +72,13 @@ To add a new Analyzer to an existing driver, add another item to the list: A driver may use the name, flags, and documentation to provide on-line help that describes the analyses its performs. +The doc comment contains a brief one-line summary, +optionally followed by paragraphs of explanation. The vet command, shown below, is an example of a driver that runs multiple analyzers. It is based on the multichecker package (see the "Standalone commands" section for details). - $ go build golang.org/x/tools/cmd/vet + $ go build golang.org/x/tools/go/analysis/cmd/vet $ ./vet help vet is a tool for static analysis of Go programs. @@ -285,6 +287,16 @@ pointed to by fact. This scheme assumes that the concrete type of fact is a pointer; this assumption is checked by the Validate function. See the "printf" analyzer for an example of object facts in action. +Some driver implementations (such as those based on Bazel and Blaze) do +not currently apply analyzers to packages of the standard library. +Therefore, for best results, analyzer authors should not rely on +analysis facts being available for standard packages. +For example, although the printf checker is capable of deducing during +analysis of the log package that log.Printf is a printf-wrapper, +this fact is built in to the analyzer so that it correctly checks +calls to log.Printf even when run in a driver that does not apply +it to standard packages. We plan to remove this limitation in future. + Testing an Analyzer @@ -298,14 +310,14 @@ diagnostics and facts (and no more). Expectations are expressed using Standalone commands Analyzers are provided in the form of packages that a driver program is -expected to import. The vet command imports a set of several analyses, +expected to import. The vet command imports a set of several analyzers, but users may wish to define their own analysis commands that perform additional checks. To simplify the task of creating an analysis command, either for a single analyzer or for a whole suite, we provide the singlechecker and multichecker subpackages. The singlechecker package provides the main function for a command that -runs one analysis. By convention, each analyzer such as +runs one analyzer. By convention, each analyzer such as go/passes/findcall should be accompanied by a singlechecker-based command such as go/analysis/passes/findcall/cmd/findcall, defined in its entirety as: diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go index d6c13f2685c8f8..729ac3b41768da 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go @@ -11,41 +11,41 @@ import ( "encoding/json" "flag" "fmt" + "go/token" "io" + "io/ioutil" "log" "os" "strconv" + "strings" "golang.org/x/tools/go/analysis" ) +// flags common to all {single,multi,unit}checkers. +var ( + JSON = false // -json + Context = -1 // -c=N: if N>0, display offending line plus N lines of context +) + // Parse creates a flag for each of the analyzer's flags, -// including (in multi mode) an --analysis.enable flag, +// including (in multi mode) a flag named after the analyzer, // parses the flags, then filters and returns the list of // analyzers enabled by flags. func Parse(analyzers []*analysis.Analyzer, multi bool) []*analysis.Analyzer { // Connect each analysis flag to the command line as -analysis.flag. - type analysisFlag struct { - Name string - Bool bool - Usage string - } - var analysisFlags []analysisFlag - enabled := make(map[*analysis.Analyzer]*triState) for _, a := range analyzers { var prefix string - // Add -analysis.enable flag. + // Add -NAME flag to enable it. if multi { prefix = a.Name + "." enable := new(triState) - enableName := prefix + "enable" enableUsage := "enable " + a.Name + " analysis" - flag.Var(enable, enableName, enableUsage) + flag.Var(enable, a.Name, enableUsage) enabled[a] = enable - analysisFlags = append(analysisFlags, analysisFlag{enableName, true, enableUsage}) } a.Flags.VisitAll(func(f *flag.Flag) { @@ -56,12 +56,6 @@ func Parse(analyzers []*analysis.Analyzer, multi bool) []*analysis.Analyzer { name := prefix + f.Name flag.Var(f.Value, name, f.Usage) - - var isBool bool - if b, ok := f.Value.(interface{ IsBoolFlag() bool }); ok { - isBool = b.IsBoolFlag() - } - analysisFlags = append(analysisFlags, analysisFlag{name, isBool, f.Usage}) }) } @@ -69,20 +63,33 @@ func Parse(analyzers []*analysis.Analyzer, multi bool) []*analysis.Analyzer { printflags := flag.Bool("flags", false, "print analyzer flags in JSON") addVersionFlag() + // flags common to all checkers + flag.BoolVar(&JSON, "json", JSON, "emit JSON output") + flag.IntVar(&Context, "c", Context, `display offending line with this many lines of context`) + + // Add shims for legacy vet flags to enable existing + // scripts that run vet to continue to work. + _ = flag.Bool("source", false, "no effect (deprecated)") + _ = flag.Bool("v", false, "no effect (deprecated)") + _ = flag.Bool("all", false, "no effect (deprecated)") + _ = flag.String("tags", "", "no effect (deprecated)") + for old, new := range vetLegacyFlags { + newFlag := flag.Lookup(new) + if newFlag != nil && flag.Lookup(old) == nil { + flag.Var(newFlag.Value, old, "deprecated alias for -"+new) + } + } + flag.Parse() // (ExitOnError) // -flags: print flags so that go vet knows which ones are legitimate. if *printflags { - data, err := json.MarshalIndent(analysisFlags, "", "\t") - if err != nil { - log.Fatal(err) - } - os.Stdout.Write(data) + printFlags() os.Exit(0) } - // If any --foo.enable flag is true, run only those analyzers. Otherwise, - // if any --foo.enable flag is false, run all but those analyzers. + // If any -NAME flag is true, run only those analyzers. Otherwise, + // if any -NAME flag is false, run all but those analyzers. if multi { var hasTrue, hasFalse bool for _, ts := range enabled { @@ -115,6 +122,33 @@ func Parse(analyzers []*analysis.Analyzer, multi bool) []*analysis.Analyzer { return analyzers } +func printFlags() { + type jsonFlag struct { + Name string + Bool bool + Usage string + } + var flags []jsonFlag = nil + flag.VisitAll(func(f *flag.Flag) { + // Don't report {single,multi}checker debugging + // flags as these have no effect on unitchecker + // (as invoked by 'go vet'). + switch f.Name { + case "debug", "cpuprofile", "memprofile", "trace": + return + } + + b, ok := f.Value.(interface{ IsBoolFlag() bool }) + isBool := ok && b.IsBoolFlag() + flags = append(flags, jsonFlag{f.Name, isBool, f.Usage}) + }) + data, err := json.MarshalIndent(flags, "", "\t") + if err != nil { + log.Fatal(err) + } + os.Stdout.Write(data) +} + // addVersionFlag registers a -V flag that, if set, // prints the executable version and exits 0. // @@ -195,7 +229,7 @@ func (ts *triState) Set(value string) error { b, err := strconv.ParseBool(value) if err != nil { // This error message looks poor but package "flag" adds - // "invalid boolean value %q for -foo.enable: %s" + // "invalid boolean value %q for -NAME: %s" return fmt.Errorf("want true or false") } if b { @@ -221,3 +255,89 @@ func (ts *triState) String() string { func (ts triState) IsBoolFlag() bool { return true } + +// Legacy flag support + +// vetLegacyFlags maps flags used by legacy vet to their corresponding +// new names. The old names will continue to work. +var vetLegacyFlags = map[string]string{ + // Analyzer name changes + "bool": "bools", + "buildtags": "buildtag", + "methods": "stdmethods", + "rangeloops": "loopclosure", + + // Analyzer flags + "compositewhitelist": "composites.whitelist", + "printfuncs": "printf.funcs", + "shadowstrict": "shadow.strict", + "unusedfuncs": "unusedresult.funcs", + "unusedstringmethods": "unusedresult.stringmethods", +} + +// ---- output helpers common to all drivers ---- + +// PrintPlain prints a diagnostic in plain text form, +// with context specified by the -c flag. +func PrintPlain(fset *token.FileSet, diag analysis.Diagnostic) { + posn := fset.Position(diag.Pos) + fmt.Fprintf(os.Stderr, "%s: %s\n", posn, diag.Message) + + // -c=N: show offending line plus N lines of context. + if Context >= 0 { + data, _ := ioutil.ReadFile(posn.Filename) + lines := strings.Split(string(data), "\n") + for i := posn.Line - Context; i <= posn.Line+Context; i++ { + if 1 <= i && i <= len(lines) { + fmt.Fprintf(os.Stderr, "%d\t%s\n", i, lines[i-1]) + } + } + } +} + +// A JSONTree is a mapping from package ID to analysis name to result. +// Each result is either a jsonError or a list of jsonDiagnostic. +type JSONTree map[string]map[string]interface{} + +// Add adds the result of analysis 'name' on package 'id'. +// The result is either a list of diagnostics or an error. +func (tree JSONTree) Add(fset *token.FileSet, id, name string, diags []analysis.Diagnostic, err error) { + var v interface{} + if err != nil { + type jsonError struct { + Err string `json:"error"` + } + v = jsonError{err.Error()} + } else if len(diags) > 0 { + type jsonDiagnostic struct { + Category string `json:"category,omitempty"` + Posn string `json:"posn"` + Message string `json:"message"` + } + var diagnostics []jsonDiagnostic + for _, f := range diags { + diagnostics = append(diagnostics, jsonDiagnostic{ + Category: f.Category, + Posn: fset.Position(f.Pos).String(), + Message: f.Message, + }) + } + v = diagnostics + } + if v != nil { + m, ok := tree[id] + if !ok { + m = make(map[string]interface{}) + tree[id] = m + } + m[name] = v + } +} + +func (tree JSONTree) Print() { + data, err := json.MarshalIndent(tree, "", "\t") + if err != nil { + log.Panicf("internal error: JSON marshalling failed: %v", err) + } + fmt.Printf("%s\n", data) +} diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/help.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/help.go new file mode 100644 index 00000000000000..66aa624572aceb --- /dev/null +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/help.go @@ -0,0 +1,89 @@ +package analysisflags + +import ( + "flag" + "fmt" + "log" + "sort" + "strings" + + "golang.org/x/tools/go/analysis" +) + +const help = `PROGNAME is a tool for static analysis of Go programs. + +PROGNAME examines Go source code and reports suspicious constructs, +such as Printf calls whose arguments do not align with the format +string. It uses heuristics that do not guarantee all reports are +genuine problems, but it can find errors not caught by the compilers. +` + +// Help implements the help subcommand for a multichecker or vet-lite +// style command. The optional args specify the analyzers to describe. +// Help calls log.Fatal if no such analyzer exists. +func Help(progname string, analyzers []*analysis.Analyzer, args []string) { + // No args: show summary of all analyzers. + if len(args) == 0 { + fmt.Println(strings.Replace(help, "PROGNAME", progname, -1)) + fmt.Println("Registered analyzers:") + fmt.Println() + sort.Slice(analyzers, func(i, j int) bool { + return analyzers[i].Name < analyzers[j].Name + }) + for _, a := range analyzers { + title := strings.Split(a.Doc, "\n\n")[0] + fmt.Printf(" %-12s %s\n", a.Name, title) + } + fmt.Println("\nBy default all analyzers are run.") + fmt.Println("To select specific analyzers, use the -NAME flag for each one,") + fmt.Println(" or -NAME=false to run all analyzers not explicitly disabled.") + + // Show only the core command-line flags. + fmt.Println("\nCore flags:") + fmt.Println() + fs := flag.NewFlagSet("", flag.ExitOnError) + flag.VisitAll(func(f *flag.Flag) { + if !strings.Contains(f.Name, ".") { + fs.Var(f.Value, f.Name, f.Usage) + } + }) + fs.PrintDefaults() + + fmt.Printf("\nTo see details and flags of a specific analyzer, run '%s help name'.\n", progname) + + return + } + + // Show help on specific analyzer(s). +outer: + for _, arg := range args { + for _, a := range analyzers { + if a.Name == arg { + paras := strings.Split(a.Doc, "\n\n") + title := paras[0] + fmt.Printf("%s: %s\n", a.Name, title) + + // Show only the flags relating to this analysis, + // properly prefixed. + first := true + fs := flag.NewFlagSet(a.Name, flag.ExitOnError) + a.Flags.VisitAll(func(f *flag.Flag) { + if first { + first = false + fmt.Println("\nAnalyzer flags:") + fmt.Println() + } + fs.Var(f.Value, a.Name+"."+f.Name, f.Usage) + }) + fs.PrintDefaults() + + if len(paras) > 1 { + fmt.Printf("\n%s\n", strings.Join(paras[1:], "\n\n")) + } + + continue outer + } + } + log.Fatalf("Analyzer %q not registered", arg) + } +} diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/patch.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/patch.go new file mode 100644 index 00000000000000..8f9741055cbac1 --- /dev/null +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/patch.go @@ -0,0 +1,7 @@ +package analysisflags + +import "cmd/internal/objabi" + +// This additional file changes the behavior of the vendored code. + +func init() { addVersionFlag = objabi.AddVersionFlag } diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go index 11dfbf6bc8e308..0f8abb5748127a 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go @@ -243,16 +243,17 @@ Files: } } if arch == "" { - badf("%s: cannot determine architecture for assembly file") + log.Printf("%s: cannot determine architecture for assembly file", fname) continue Files } } fnName = m[2] - if pkgName := strings.TrimSpace(m[1]); pkgName != "" { - pathParts := strings.Split(pkgName, "∕") - pkgName = pathParts[len(pathParts)-1] - if pkgName != pass.Pkg.Path() { - badf("[%s] cannot check cross-package assembly function: %s is in package %s", arch, fnName, pkgName) + if pkgPath := strings.TrimSpace(m[1]); pkgPath != "" { + // The assembler uses Unicode division slash within + // identifiers to represent the directory separator. + pkgPath = strings.Replace(pkgPath, "∕", "/", -1) + if pkgPath != pass.Pkg.Path() { + log.Printf("%s:%d: [%s] cannot check cross-package assembly function: %s is in package %s", fname, lineno, arch, fnName, pkgPath) fn = nil fnName = "" continue diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go index 7eb24a4a91e61f..993f1ce3c4b4ac 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go @@ -9,18 +9,22 @@ package cgocall import ( "fmt" "go/ast" + "go/build" + "go/format" + "go/parser" "go/token" "go/types" "log" - "strings" + "os" + "strconv" "golang.org/x/tools/go/analysis" - "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" - "golang.org/x/tools/go/ast/inspector" ) -const Doc = `detect some violations of the cgo pointer passing rules +const debug = false + +const doc = `detect some violations of the cgo pointer passing rules Check for invalid cgo pointer passing. This looks for code that uses cgo to call C code passing values @@ -31,24 +35,41 @@ or slice to C, either directly, or via a pointer, array, or struct.` var Analyzer = &analysis.Analyzer{ Name: "cgocall", - Doc: Doc, - Requires: []*analysis.Analyzer{inspect.Analyzer}, + Doc: doc, RunDespiteErrors: true, Run: run, } func run(pass *analysis.Pass) (interface{}, error) { - inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + if imports(pass.Pkg, "runtime/cgo") == nil { + return nil, nil // doesn't use cgo + } - nodeFilter := []ast.Node{ - (*ast.CallExpr)(nil), + cgofiles, info, err := typeCheckCgoSourceFiles(pass.Fset, pass.Pkg, pass.Files, pass.TypesInfo) + if err != nil { + return nil, err + } + for _, f := range cgofiles { + checkCgo(pass.Fset, f, info, pass.Reportf) } - inspect.WithStack(nodeFilter, func(n ast.Node, push bool, stack []ast.Node) bool { - if !push { + return nil, nil +} + +func checkCgo(fset *token.FileSet, f *ast.File, info *types.Info, reportf func(token.Pos, string, ...interface{})) { + ast.Inspect(f, func(n ast.Node) bool { + call, ok := n.(*ast.CallExpr) + if !ok { return true } - call, name := findCall(pass.Fset, stack) - if call == nil { + + // Is this a C.f() call? + var name string + if sel, ok := analysisutil.Unparen(call.Fun).(*ast.SelectorExpr); ok { + if id, ok := sel.X.(*ast.Ident); ok && id.Name == "C" { + name = sel.Sel.Name + } + } + if name == "" { return true // not a call we need to check } @@ -57,92 +78,210 @@ func run(pass *analysis.Pass) (interface{}, error) { return true } - if false { - fmt.Printf("%s: inner call to C.%s\n", pass.Fset.Position(n.Pos()), name) - fmt.Printf("%s: outer call to C.%s\n", pass.Fset.Position(call.Lparen), name) + if debug { + log.Printf("%s: call to C.%s", fset.Position(call.Lparen), name) } for _, arg := range call.Args { - if !typeOKForCgoCall(cgoBaseType(pass.TypesInfo, arg), make(map[types.Type]bool)) { - pass.Reportf(arg.Pos(), "possibly passing Go type with embedded pointer to C") + if !typeOKForCgoCall(cgoBaseType(info, arg), make(map[types.Type]bool)) { + reportf(arg.Pos(), "possibly passing Go type with embedded pointer to C") break } // Check for passing the address of a bad type. if conv, ok := arg.(*ast.CallExpr); ok && len(conv.Args) == 1 && - isUnsafePointer(pass.TypesInfo, conv.Fun) { + isUnsafePointer(info, conv.Fun) { arg = conv.Args[0] } if u, ok := arg.(*ast.UnaryExpr); ok && u.Op == token.AND { - if !typeOKForCgoCall(cgoBaseType(pass.TypesInfo, u.X), make(map[types.Type]bool)) { - pass.Reportf(arg.Pos(), "possibly passing Go type with embedded pointer to C") + if !typeOKForCgoCall(cgoBaseType(info, u.X), make(map[types.Type]bool)) { + reportf(arg.Pos(), "possibly passing Go type with embedded pointer to C") break } } } return true }) - return nil, nil } -// findCall returns the CallExpr that we need to check, which may not be -// the same as the one we're currently visiting, due to code generation. -// It also returns the name of the function, such as "f" for C.f(...). -// -// This checker was initially written in vet to inpect unprocessed cgo -// source files using partial type information. However, Analyzers in -// the new analysis API are presented with the type-checked, processed -// Go ASTs resulting from cgo processing files, so we must choose -// between: +// typeCheckCgoSourceFiles returns type-checked syntax trees for the raw +// cgo files of a package (those that import "C"). Such files are not +// Go, so there may be gaps in type information around C.f references. // -// a) locating the cgo file (e.g. from //line directives) -// and working with that, or -// b) working with the file generated by cgo. +// This checker was initially written in vet to inpect raw cgo source +// files using partial type information. However, Analyzers in the new +// analysis API are presented with the type-checked, "cooked" Go ASTs +// resulting from cgo-processing files, so we must choose between +// working with the cooked file generated by cgo (which was tried but +// proved fragile) or locating the raw cgo file (e.g. from //line +// directives) and working with that, as we now do. // -// We cannot use (a) because it does not provide type information, which -// the analyzer needs, and it is infeasible for the analyzer to run the -// type checker on this file. Thus we choose (b), which is fragile, -// because the checker may need to change each time the cgo processor -// changes. +// Specifically, we must type-check the raw cgo source files (or at +// least the subtrees needed for this analyzer) in an environment that +// simulates the rest of the already type-checked package. // -// Consider a cgo source file containing this header: +// For example, for each raw cgo source file in the original package, +// such as this one: // -// /* void f(void *x, *y); */ -// import "C" +// package p +// import "C" +// import "fmt" +// type T int +// const k = 3 +// var x, y = fmt.Println() +// func f() { ... } +// func g() { ... C.malloc(k) ... } +// func (T) f(int) string { ... } // -// The cgo tool expands a call such as: +// we synthesize a new ast.File, shown below, that dot-imports the +// orginal "cooked" package using a special name ("·this·"), so that all +// references to package members resolve correctly. (References to +// unexported names cause an "unexported" error, which we ignore.) // -// C.f(x, y) +// To avoid shadowing names imported from the cooked package, +// package-level declarations in the new source file are modified so +// that they do not declare any names. +// (The cgocall analysis is concerned with uses, not declarations.) +// Specifically, type declarations are discarded; +// all names in each var and const declaration are blanked out; +// each method is turned into a regular function by turning +// the receiver into the first parameter; +// and all functions are renamed to "_". // -// to this: +// package p +// import . "·this·" // declares T, k, x, y, f, g, T.f +// import "C" +// import "fmt" +// const _ = 3 +// var _, _ = fmt.Println() +// func _() { ... } +// func _() { ... C.malloc(k) ... } +// func _(T, int) string { ... } // -// 1 func(param0, param1 unsafe.Pointer) { -// 2 ... various checks on params ... -// 3 (_Cfunc_f)(param0, param1) -// 4 }(x, y) +// In this way, the raw function bodies and const/var initializer +// expressions are preserved but refer to the "cooked" objects imported +// from "·this·", and none of the transformed package-level declarations +// actually declares anything. In the example above, the reference to k +// in the argument of the call to C.malloc resolves to "·this·".k, which +// has an accurate type. // -// We first locate the _Cfunc_f call on line 3, then -// walk up the stack of enclosing nodes until we find -// the call on line 4. +// This approach could in principle be generalized to more complex +// analyses on raw cgo files. One could synthesize a "C" package so that +// C.f would resolve to "·this·"._C_func_f, for example. But we have +// limited ourselves here to preserving function bodies and initializer +// expressions since that is all that the cgocall analyzer needs. // -func findCall(fset *token.FileSet, stack []ast.Node) (*ast.CallExpr, string) { - last := len(stack) - 1 - call := stack[last].(*ast.CallExpr) - if id, ok := analysisutil.Unparen(call.Fun).(*ast.Ident); ok { - if name := strings.TrimPrefix(id.Name, "_Cfunc_"); name != id.Name { - // Find the outer call with the arguments (x, y) we want to check. - for i := last - 1; i >= 0; i-- { - if outer, ok := stack[i].(*ast.CallExpr); ok { - return outer, name +func typeCheckCgoSourceFiles(fset *token.FileSet, pkg *types.Package, files []*ast.File, info *types.Info) ([]*ast.File, *types.Info, error) { + const thispkg = "·this·" + + // Which files are cgo files? + var cgoFiles []*ast.File + importMap := map[string]*types.Package{thispkg: pkg} + for _, raw := range files { + // If f is a cgo-generated file, Position reports + // the original file, honoring //line directives. + filename := fset.Position(raw.Pos()).Filename + f, err := parser.ParseFile(fset, filename, nil, parser.Mode(0)) + if err != nil { + return nil, nil, fmt.Errorf("can't parse raw cgo file: %v", err) + } + found := false + for _, spec := range f.Imports { + if spec.Path.Value == `"C"` { + found = true + break + } + } + if !found { + continue // not a cgo file + } + + // Record the original import map. + for _, spec := range raw.Imports { + path, _ := strconv.Unquote(spec.Path.Value) + importMap[path] = imported(info, spec) + } + + // Add special dot-import declaration: + // import . "·this·" + var decls []ast.Decl + decls = append(decls, &ast.GenDecl{ + Tok: token.IMPORT, + Specs: []ast.Spec{ + &ast.ImportSpec{ + Name: &ast.Ident{Name: "."}, + Path: &ast.BasicLit{ + Kind: token.STRING, + Value: strconv.Quote(thispkg), + }, + }, + }, + }) + + // Transform declarations from the raw cgo file. + for _, decl := range f.Decls { + switch decl := decl.(type) { + case *ast.GenDecl: + switch decl.Tok { + case token.TYPE: + // Discard type declarations. + continue + case token.IMPORT: + // Keep imports. + case token.VAR, token.CONST: + // Blank the declared var/const names. + for _, spec := range decl.Specs { + spec := spec.(*ast.ValueSpec) + for i := range spec.Names { + spec.Names[i].Name = "_" + } + } + } + case *ast.FuncDecl: + // Blank the declared func name. + decl.Name.Name = "_" + + // Turn a method receiver: func (T) f(P) R {...} + // into regular parameter: func _(T, P) R {...} + if decl.Recv != nil { + var params []*ast.Field + params = append(params, decl.Recv.List...) + params = append(params, decl.Type.Params.List...) + decl.Type.Params.List = params + decl.Recv = nil } } - // This shouldn't happen. - // Perhaps the code generator has changed? - log.Printf("%s: can't find outer call for C.%s(...)", - fset.Position(call.Lparen), name) + decls = append(decls, decl) + } + f.Decls = decls + if debug { + format.Node(os.Stderr, fset, f) // debugging } + cgoFiles = append(cgoFiles, f) + } + if cgoFiles == nil { + return nil, nil, nil // nothing to do (can't happen?) + } + + // Type-check the synthetic files. + tc := &types.Config{ + FakeImportC: true, + Importer: importerFunc(func(path string) (*types.Package, error) { + return importMap[path], nil + }), + // TODO(adonovan): Sizes should probably be provided by analysis.Pass. + Sizes: types.SizesFor("gc", build.Default.GOARCH), + Error: func(error) {}, // ignore errors (e.g. unused import) + } + + // It's tempting to record the new types in the + // existing pass.TypesInfo, but we don't own it. + altInfo := &types.Info{ + Types: make(map[ast.Expr]types.TypeAndValue), } - return nil, "" + tc.Check(pkg.Path(), fset, cgoFiles, altInfo) + + return cgoFiles, altInfo, nil } // cgoBaseType tries to look through type conversions involving @@ -224,3 +363,28 @@ func isUnsafePointer(info *types.Info, e ast.Expr) bool { t := info.Types[e].Type return t != nil && t.Underlying() == types.Typ[types.UnsafePointer] } + +type importerFunc func(path string) (*types.Package, error) + +func (f importerFunc) Import(path string) (*types.Package, error) { return f(path) } + +// TODO(adonovan): make this a library function or method of Info. +func imported(info *types.Info, spec *ast.ImportSpec) *types.Package { + obj, ok := info.Implicits[spec] + if !ok { + obj = info.Defs[spec.Name] // renaming import + } + return obj.(*types.PkgName).Imported() +} + +// imports reports whether pkg has path among its direct imports. +// It returns the imported package if so, or nil if not. +// TODO(adonovan): move to analysisutil. +func imports(pkg *types.Package, path string) *types.Package { + for _, imp := range pkg.Imports() { + if imp.Path() == path { + return imp + } + } + return nil +} diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go index b7cfe8a95d365a..9cca7781d00442 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go @@ -16,7 +16,7 @@ import ( "golang.org/x/tools/go/ast/inspector" ) -const Doc = `checked for unkeyed composite literals +const Doc = `check for unkeyed composite literals This analyzer reports a diagnostic for composite literals of struct types imported from another package that do not use the field-keyed diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go index fcf9f553a9f0b8..b5161836a57a23 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go @@ -93,32 +93,32 @@ func runFunc(pass *analysis.Pass, node ast.Node) { // ctx, cancel = context.WithCancel(...) // var ctx, cancel = context.WithCancel(...) // - if isContextWithCancel(pass.TypesInfo, 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 !isContextWithCancel(pass.TypesInfo, n) || !isCall(stack[len(stack)-2]) { + return true + } + 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] } - if id != nil { - if id.Name == "_" { - pass.Reportf(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 := pass.TypesInfo.Uses[id].(*types.Var); ok { - cancelvars[v] = stmt - } else if v, ok := pass.TypesInfo.Defs[id].(*types.Var); ok { - cancelvars[v] = stmt - } + case *ast.AssignStmt: + if len(stmt.Lhs) > 1 { + id, _ = stmt.Lhs[1].(*ast.Ident) + } + } + if id != nil { + if id.Name == "_" { + pass.Reportf(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 := pass.TypesInfo.Uses[id].(*types.Var); ok { + cancelvars[v] = stmt + } else if v, ok := pass.TypesInfo.Defs[id].(*types.Var); ok { + cancelvars[v] = stmt } } - return true }) @@ -132,11 +132,17 @@ func runFunc(pass *analysis.Pass, node ast.Node) { var sig *types.Signature switch node := node.(type) { case *ast.FuncDecl: - g = cfgs.FuncDecl(node) sig, _ = pass.TypesInfo.Defs[node.Name].Type().(*types.Signature) + if node.Name.Name == "main" && sig.Recv() == nil && pass.Pkg.Name() == "main" { + // Returning from main.main terminates the process, + // so there's no need to cancel contexts. + return + } + g = cfgs.FuncDecl(node) + case *ast.FuncLit: - g = cfgs.FuncLit(node) sig, _ = pass.TypesInfo.Types[node.Type].Type.(*types.Signature) + g = cfgs.FuncLit(node) } if sig == nil { return // missing type information @@ -173,18 +179,22 @@ func hasImport(pkg *types.Package, path string) bool { // isContextWithCancel reports whether n is one of the qualified identifiers // context.With{Cancel,Timeout,Deadline}. func isContextWithCancel(info *types.Info, 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 := info.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" - } + sel, ok := n.(*ast.SelectorExpr) + if !ok { + return false + } + switch sel.Sel.Name { + case "WithCancel", "WithTimeout", "WithDeadline": + default: + return false + } + if x, ok := sel.X.(*ast.Ident); ok { + if pkgname, ok := info.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 } @@ -264,29 +274,30 @@ outer: 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 + if seen[b] { + continue + } + seen[b] = true - // Prune the search if the block uses v. - if blockUses(pass, v, b) { - continue - } + // Prune the search if the block uses v. + if blockUses(pass, v, b) { + continue + } - // Found path to return statement? - if ret := b.Return(); ret != nil { - if debug { - fmt.Printf("found path to return in block %s\n", b) - } - return ret // found + // Found path to return statement? + if ret := b.Return(); ret != nil { + if debug { + fmt.Printf("found path to return in block %s\n", b) } + return ret // found + } - // Recur - if ret := search(b.Succs); ret != nil { - if debug { - fmt.Printf(" from block %s\n", b) - } - return ret + // Recur + if ret := search(b.Succs); ret != nil { + if debug { + fmt.Printf(" from block %s\n", b) } + return ret } } return nil diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go index 23f634fd98eb0b..9fa0a1c603c7d2 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go @@ -32,7 +32,7 @@ func init() { var Analyzer = &analysis.Analyzer{ Name: "printf", - Doc: "check printf-like invocations", + Doc: doc, Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: run, FactTypes: []analysis.Fact{new(isWrapper)}, @@ -43,12 +43,12 @@ const doc = `check consistency of Printf format strings and arguments The check applies to known functions (for example, those in package fmt) as well as any detected wrappers of known functions. -A function that wants to avail itself of printf checking but does not -get found by this analyzer's heuristics (for example, due to use of +A function that wants to avail itself of printf checking but is not +found by this analyzer's heuristics (for example, due to use of dynamic calls) can insert a bogus call: if false { - fmt.Sprintf(format, args...) // enable printf checking + _ = fmt.Sprintf(format, args...) // enable printf checking } The -funcs flag specifies a comma-separated list of names of additional @@ -277,18 +277,56 @@ func checkPrintfFwd(pass *analysis.Pass, w *printfWrapper, call *ast.CallExpr, k // or case-insensitive identifiers such as "errorf". // // The -funcs flag adds to this set. +// +// The set below includes facts for many important standard library +// functions, even though the analysis is capable of deducing that, for +// example, fmt.Printf forwards to fmt.Fprintf. We avoid relying on the +// driver applying analyzers to standard packages because "go vet" does +// not do so with gccgo, and nor do some other build systems. +// TODO(adonovan): eliminate the redundant facts once this restriction +// is lifted. +// var isPrint = stringSet{ "fmt.Errorf": true, "fmt.Fprint": true, "fmt.Fprintf": true, "fmt.Fprintln": true, - "fmt.Print": true, // technically these three - "fmt.Printf": true, // are redundant because they - "fmt.Println": true, // forward to Fprint{,f,ln} + "fmt.Print": true, + "fmt.Printf": true, + "fmt.Println": true, "fmt.Sprint": true, "fmt.Sprintf": true, "fmt.Sprintln": true, + "runtime/trace.Logf": true, + + "log.Print": true, + "log.Printf": true, + "log.Println": true, + "log.Fatal": true, + "log.Fatalf": true, + "log.Fatalln": true, + "log.Panic": true, + "log.Panicf": true, + "log.Panicln": true, + "(*log.Logger).Fatal": true, + "(*log.Logger).Fatalf": true, + "(*log.Logger).Fatalln": true, + "(*log.Logger).Panic": true, + "(*log.Logger).Panicf": true, + "(*log.Logger).Panicln": true, + "(*log.Logger).Print": true, + "(*log.Logger).Printf": true, + "(*log.Logger).Println": true, + + "(*testing.common).Error": true, + "(*testing.common).Errorf": true, + "(*testing.common).Fatal": true, + "(*testing.common).Fatalf": true, + "(*testing.common).Log": true, + "(*testing.common).Logf": true, + "(*testing.common).Skip": true, + "(*testing.common).Skipf": true, // *testing.T and B are detected by induction, but testing.TB is // an interface and the inference can't follow dynamic calls. "(testing.TB).Error": true, @@ -805,7 +843,22 @@ func recursiveStringer(pass *analysis.Pass, e ast.Expr) bool { } // Is the expression e within the body of that String method? - return stringMethod.Pkg() == pass.Pkg && stringMethod.Scope().Contains(e.Pos()) + if stringMethod.Pkg() != pass.Pkg || !stringMethod.Scope().Contains(e.Pos()) { + return false + } + + // Is it the receiver r, or &r? + recv := stringMethod.Type().(*types.Signature).Recv() + if recv == nil { + return false + } + if u, ok := e.(*ast.UnaryExpr); ok && u.Op == token.AND { + e = u.X // strip off & from &r + } + if id, ok := e.(*ast.Ident); ok { + return pass.TypesInfo.Uses[id] == recv + } + return false } // isFunctionValue reports whether the expression is a function as opposed to a function call. diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/types.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/types.go index 701d08bea2bb12..0ebc8107f3db80 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/types.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/types.go @@ -97,12 +97,25 @@ func matchArgTypeInternal(pass *analysis.Pass, t printfArgType, typ types.Type, 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 matchStructArgType(pass, t, str, arg, inProgress) + + under := typ.Elem().Underlying() + switch under.(type) { + case *types.Struct: // see below + case *types.Array: // see below + case *types.Slice: // see below + case *types.Map: // see below + default: + // Check whether the rest can print pointers. + return t&argPointer != 0 } - // Check whether the rest can print pointers. - return t&argPointer != 0 + // If it's a top-level pointer to a struct, array, slice, or + // map, that's equivalent in our analysis to whether we can + // print the type being pointed to. Pointers in nested levels + // are not supported to minimize fmt running into loops. + if len(inProgress) > 1 { + return false + } + return matchArgTypeInternal(pass, t, under, arg, inProgress) case *types.Struct: return matchStructArgType(pass, t, typ, arg, inProgress) diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go index eead289e4ccbad..83495112243a44 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go @@ -7,10 +7,7 @@ package stdmethods import ( - "bytes" - "fmt" "go/ast" - "go/printer" "go/token" "go/types" "strings" @@ -95,12 +92,12 @@ func run(pass *analysis.Pass) (interface{}, error) { switch n := n.(type) { case *ast.FuncDecl: if n.Recv != nil { - canonicalMethod(pass, n.Name, n.Type) + canonicalMethod(pass, n.Name) } case *ast.InterfaceType: for _, field := range n.Methods.List { for _, id := range field.Names { - canonicalMethod(pass, id, field.Type.(*ast.FuncType)) + canonicalMethod(pass, id) } } } @@ -108,7 +105,7 @@ func run(pass *analysis.Pass) (interface{}, error) { return nil, nil } -func canonicalMethod(pass *analysis.Pass, id *ast.Ident, t *ast.FuncType) { +func canonicalMethod(pass *analysis.Pass, id *ast.Ident) { // Expected input/output. expect, ok := canonicalMethods[id.Name] if !ok { @@ -116,11 +113,9 @@ func canonicalMethod(pass *analysis.Pass, id *ast.Ident, t *ast.FuncType) { } // Actual input/output - args := typeFlatten(t.Params.List) - var results []ast.Expr - if t.Results != nil { - results = typeFlatten(t.Results.List) - } + sign := pass.TypesInfo.Defs[id].Type().(*types.Signature) + args := sign.Params() + results := sign.Results() // Do the =s (if any) all match? if !matchParams(pass, expect.args, args, "=") || !matchParams(pass, expect.results, results, "=") { @@ -136,11 +131,7 @@ func canonicalMethod(pass *analysis.Pass, id *ast.Ident, t *ast.FuncType) { expectFmt += " (" + argjoin(expect.results) + ")" } - var buf bytes.Buffer - if err := printer.Fprint(&buf, pass.Fset, t); err != nil { - fmt.Fprintf(&buf, "<%s>", err) - } - actual := buf.String() + actual := typeString(sign) actual = strings.TrimPrefix(actual, "func") actual = id.Name + actual @@ -148,6 +139,10 @@ func canonicalMethod(pass *analysis.Pass, id *ast.Ident, t *ast.FuncType) { } } +func typeString(typ types.Type) string { + return types.TypeString(typ, (*types.Package).Name) +} + func argjoin(x []string) string { y := make([]string, len(x)) for i, s := range x { @@ -159,45 +154,27 @@ func argjoin(x []string) string { 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 matchParams(pass *analysis.Pass, expect []string, actual []ast.Expr, prefix string) bool { +func matchParams(pass *analysis.Pass, expect []string, actual *types.Tuple, prefix string) bool { for i, x := range expect { if !strings.HasPrefix(x, prefix) { continue } - if i >= len(actual) { + if i >= actual.Len() { return false } - if !matchParamType(pass.Fset, pass.Pkg, x, actual[i]) { + if !matchParamType(pass.Fset, pass.Pkg, x, actual.At(i).Type()) { return false } } - if prefix == "" && len(actual) > len(expect) { + if prefix == "" && actual.Len() > len(expect) { return false } return true } // Does this one type match? -func matchParamType(fset *token.FileSet, pkg *types.Package, expect string, actual ast.Expr) bool { +func matchParamType(fset *token.FileSet, pkg *types.Package, expect string, actual types.Type) bool { expect = strings.TrimPrefix(expect, "=") // Strip package name if we're in that package. if n := len(pkg.Name()); len(expect) > n && expect[:n] == pkg.Name() && expect[n] == '.' { @@ -205,7 +182,5 @@ func matchParamType(fset *token.FileSet, pkg *types.Package, expect string, actu } // Overkill but easy. - var buf bytes.Buffer - printer.Fprint(&buf, fset, actual) - return buf.String() == expect + return typeString(actual) == expect } diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go new file mode 100644 index 00000000000000..6cf4358ab9a31f --- /dev/null +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go @@ -0,0 +1,92 @@ +// 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. + +// The unmarshal package defines an Analyzer that checks for passing +// non-pointer or non-interface types to unmarshal and decode functions. +package unmarshal + +import ( + "go/ast" + "go/types" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/ast/inspector" + "golang.org/x/tools/go/types/typeutil" +) + +const doc = `report passing non-pointer or non-interface values to unmarshal + +The unmarshal analysis reports calls to functions such as json.Unmarshal +in which the argument type is not a pointer or an interface.` + +var Analyzer = &analysis.Analyzer{ + Name: "unmarshal", + Doc: doc, + Requires: []*analysis.Analyzer{inspect.Analyzer}, + Run: run, +} + +func run(pass *analysis.Pass) (interface{}, error) { + inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + + nodeFilter := []ast.Node{ + (*ast.CallExpr)(nil), + } + inspect.Preorder(nodeFilter, func(n ast.Node) { + call := n.(*ast.CallExpr) + fn := typeutil.StaticCallee(pass.TypesInfo, call) + if fn == nil { + return // not a static call + } + + // Classify the callee (without allocating memory). + argidx := -1 + recv := fn.Type().(*types.Signature).Recv() + if fn.Name() == "Unmarshal" && recv == nil { + // "encoding/json".Unmarshal + // "encoding/xml".Unmarshal + switch fn.Pkg().Path() { + case "encoding/json", "encoding/xml": + argidx = 1 // func([]byte, interface{}) + } + } else if fn.Name() == "Decode" && recv != nil { + // (*"encoding/json".Decoder).Decode + // (* "encoding/gob".Decoder).Decode + // (* "encoding/xml".Decoder).Decode + t := recv.Type() + if ptr, ok := t.(*types.Pointer); ok { + t = ptr.Elem() + } + tname := t.(*types.Named).Obj() + if tname.Name() == "Decoder" { + switch tname.Pkg().Path() { + case "encoding/json", "encoding/xml", "encoding/gob": + argidx = 0 // func(interface{}) + } + } + } + if argidx < 0 { + return // not a function we are interested in + } + + if len(call.Args) < argidx+1 { + return // not enough arguments, e.g. called with return values of another function + } + + t := pass.TypesInfo.Types[call.Args[argidx]].Type + switch t.Underlying().(type) { + case *types.Pointer, *types.Interface: + return + } + + switch argidx { + case 0: + pass.Reportf(call.Lparen, "call of %s passes non-pointer", fn.Name()) + case 1: + pass.Reportf(call.Lparen, "call of %s passes non-pointer as second argument", fn.Name()) + } + }) + return nil, nil +} diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go index 116d622b362af1..308bfc69cb44d5 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go @@ -62,28 +62,28 @@ func isSafeUintptr(info *types.Info, x ast.Expr) bool { return isSafeUintptr(info, 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 := info.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 - } + if x.Sel.Name != "Data" { + break + } + // 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 := info.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 } } } diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/internal/unitchecker/unitchecker.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go similarity index 73% rename from src/cmd/vendor/golang.org/x/tools/go/analysis/internal/unitchecker/unitchecker.go rename to src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go index b67c943b4e261e..59489f92da16fc 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/internal/unitchecker/unitchecker.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go @@ -6,7 +6,7 @@ // driver that analyzes a single compilation unit during a build. // It is invoked by a build system such as "go vet": // -// $ GOVETTOOL=$(which vet) go vet +// $ go vet -vettool=$(which vet) // // It supports the following command-line protocol: // @@ -25,11 +25,11 @@ package unitchecker // so we will not get to analyze it. Yet we must in order // to create base facts for, say, the fmt package for the // printf checker. -// - support JSON output, factored with multichecker. import ( "encoding/gob" "encoding/json" + "flag" "fmt" "go/ast" "go/build" @@ -41,12 +41,14 @@ import ( "io/ioutil" "log" "os" + "path/filepath" "sort" "strings" "sync" "time" "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/internal/analysisflags" "golang.org/x/tools/go/analysis/internal/facts" ) @@ -54,11 +56,12 @@ import ( // It is provided to the tool in a JSON-encoded file // whose name ends with ".cfg". type Config struct { + ID string // e.g. "fmt [fmt.test]" Compiler string Dir string ImportPath string GoFiles []string - OtherFiles []string // TODO(adonovan): make go vet populate this (github.com/golang/go/issues/27665) + NonGoFiles []string ImportMap map[string]string PackageFile map[string]string Standard map[string]bool @@ -68,25 +71,93 @@ type Config struct { SucceedOnTypecheckFailure bool } -// Main reads the *.cfg file, runs the analysis, +// Main is the main function of a vet-like analysis tool that must be +// invoked by a build system to analyze a single package. +// +// The protocol required by 'go vet -vettool=...' is that the tool must support: +// +// -flags describe flags in JSON +// -V=full describe executable for build caching +// foo.cfg perform separate modular analyze on the single +// unit described by a JSON config file foo.cfg. +// +func Main(analyzers ...*analysis.Analyzer) { + progname := filepath.Base(os.Args[0]) + log.SetFlags(0) + log.SetPrefix(progname + ": ") + + if err := analysis.Validate(analyzers); err != nil { + log.Fatal(err) + } + + flag.Usage = func() { + fmt.Fprintf(os.Stderr, `%[1]s is a tool for static analysis of Go programs. + +Usage of %[1]s: + %.16[1]s unit.cfg # execute analysis specified by config file + %.16[1]s help # general help + %.16[1]s help name # help on specific analyzer and its flags +`, progname) + os.Exit(1) + } + + analyzers = analysisflags.Parse(analyzers, true) + + args := flag.Args() + if len(args) == 0 { + flag.Usage() + } + if args[0] == "help" { + analysisflags.Help(progname, analyzers, args[1:]) + os.Exit(0) + } + if len(args) != 1 || !strings.HasSuffix(args[0], ".cfg") { + log.Fatalf("invalid command: want .cfg file (this reduced version of %s is intended to be run only by the 'go vet' command)", progname) + } + Run(args[0], analyzers) +} + +// Run reads the *.cfg file, runs the analysis, // and calls os.Exit with an appropriate error code. -func Main(configFile string, analyzers []*analysis.Analyzer) { +// It assumes flags have already been set. +func Run(configFile string, analyzers []*analysis.Analyzer) { cfg, err := readConfig(configFile) if err != nil { log.Fatal(err) } fset := token.NewFileSet() - diags, err := run(fset, cfg, analyzers) + results, err := run(fset, cfg, analyzers) if err != nil { log.Fatal(err) } - if len(diags) > 0 { - for _, diag := range diags { - fmt.Fprintf(os.Stderr, "%s: %s\n", fset.Position(diag.Pos), diag.Message) + // In VetxOnly mode, the analysis is run only for facts. + if !cfg.VetxOnly { + if analysisflags.JSON { + // JSON output + tree := make(analysisflags.JSONTree) + for _, res := range results { + tree.Add(fset, cfg.ID, res.a.Name, res.diagnostics, res.err) + } + tree.Print() + } else { + // plain text + exit := 0 + for _, res := range results { + if res.err != nil { + log.Println(res.err) + exit = 1 + } + } + for _, res := range results { + for _, diag := range res.diagnostics { + analysisflags.PrintPlain(fset, diag) + exit = 1 + } + } + os.Exit(exit) } - os.Exit(1) } os.Exit(0) @@ -110,7 +181,7 @@ func readConfig(filename string) (*Config, error) { return cfg, nil } -func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]analysis.Diagnostic, error) { +func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]result, error) { // Load, parse, typecheck. var files []*ast.File for _, name := range cfg.GoFiles { @@ -250,7 +321,7 @@ func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]an Analyzer: a, Fset: fset, Files: files, - OtherFiles: cfg.OtherFiles, + OtherFiles: cfg.NonGoFiles, Pkg: pkg, TypesInfo: info, ResultOf: inputs, @@ -283,14 +354,13 @@ func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]an execAll(analyzers) - // Return diagnostics from root analyzers. - var diags []analysis.Diagnostic - for _, a := range analyzers { + // Return diagnostics and errors from root analyzers. + results := make([]result, len(analyzers)) + for i, a := range analyzers { act := actions[a] - if act.err != nil { - return nil, act.err // some analysis failed - } - diags = append(diags, act.diagnostics...) + results[i].a = a + results[i].err = act.err + results[i].diagnostics = act.diagnostics } data := facts.Encode() @@ -298,7 +368,13 @@ func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]an return nil, fmt.Errorf("failed to write analysis facts: %v", err) } - return diags, nil + return results, nil +} + +type result struct { + a *analysis.Analyzer + diagnostics []analysis.Diagnostic + err error } type importerFunc func(path string) (*types.Package, error) diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/vet b/src/cmd/vendor/golang.org/x/tools/go/analysis/vet new file mode 100755 index 00000000000000..43c55a2fad43d9 Binary files /dev/null and b/src/cmd/vendor/golang.org/x/tools/go/analysis/vet differ diff --git a/src/cmd/vendor/golang.org/x/tools/go/ast/astutil/imports.go b/src/cmd/vendor/golang.org/x/tools/go/ast/astutil/imports.go index 04ad6795d921eb..3e4b195368b35d 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/ast/astutil/imports.go +++ b/src/cmd/vendor/golang.org/x/tools/go/ast/astutil/imports.go @@ -14,26 +14,26 @@ import ( ) // AddImport adds the import path to the file f, if absent. -func AddImport(fset *token.FileSet, f *ast.File, ipath string) (added bool) { - return AddNamedImport(fset, f, "", ipath) +func AddImport(fset *token.FileSet, f *ast.File, path string) (added bool) { + return AddNamedImport(fset, f, "", path) } -// AddNamedImport adds the import path to the file f, if absent. +// AddNamedImport adds the import with the given name and path to the file f, if absent. // If name is not empty, it is used to rename the import. // // For example, calling // AddNamedImport(fset, f, "pathpkg", "path") // adds // import pathpkg "path" -func AddNamedImport(fset *token.FileSet, f *ast.File, name, ipath string) (added bool) { - if imports(f, ipath) { +func AddNamedImport(fset *token.FileSet, f *ast.File, name, path string) (added bool) { + if imports(f, name, path) { return false } newImport := &ast.ImportSpec{ Path: &ast.BasicLit{ Kind: token.STRING, - Value: strconv.Quote(ipath), + Value: strconv.Quote(path), }, } if name != "" { @@ -43,14 +43,14 @@ func AddNamedImport(fset *token.FileSet, f *ast.File, name, ipath string) (added // Find an import decl to add to. // The goal is to find an existing import // whose import path has the longest shared - // prefix with ipath. + // prefix with path. var ( bestMatch = -1 // length of longest shared prefix lastImport = -1 // index in f.Decls of the file's final import decl impDecl *ast.GenDecl // import decl containing the best match impIndex = -1 // spec index in impDecl containing the best match - isThirdPartyPath = isThirdParty(ipath) + isThirdPartyPath = isThirdParty(path) ) for i, decl := range f.Decls { gen, ok := decl.(*ast.GenDecl) @@ -81,7 +81,7 @@ func AddNamedImport(fset *token.FileSet, f *ast.File, name, ipath string) (added for j, spec := range gen.Specs { impspec := spec.(*ast.ImportSpec) p := importPath(impspec) - n := matchLen(p, ipath) + n := matchLen(p, path) if n > bestMatch || (bestMatch == 0 && !seenAnyThirdParty && isThirdPartyPath) { bestMatch = n impDecl = gen @@ -197,11 +197,13 @@ func isThirdParty(importPath string) bool { } // DeleteImport deletes the import path from the file f, if present. +// If there are duplicate import declarations, all matching ones are deleted. func DeleteImport(fset *token.FileSet, f *ast.File, path string) (deleted bool) { return DeleteNamedImport(fset, f, "", path) } // DeleteNamedImport deletes the import with the given name and path from the file f, if present. +// If there are duplicate import declarations, all matching ones are deleted. func DeleteNamedImport(fset *token.FileSet, f *ast.File, name, path string) (deleted bool) { var delspecs []*ast.ImportSpec var delcomments []*ast.CommentGroup @@ -216,13 +218,7 @@ func DeleteNamedImport(fset *token.FileSet, f *ast.File, name, path string) (del for j := 0; j < len(gen.Specs); j++ { spec := gen.Specs[j] impspec := spec.(*ast.ImportSpec) - if impspec.Name == nil && name != "" { - continue - } - if impspec.Name != nil && impspec.Name.Name != name { - continue - } - if importPath(impspec) != path { + if importName(impspec) != name || importPath(impspec) != path { continue } @@ -383,9 +379,14 @@ func (fn visitFn) Visit(node ast.Node) ast.Visitor { return fn } -// imports returns true if f imports path. -func imports(f *ast.File, path string) bool { - return importSpec(f, path) != nil +// imports reports whether f has an import with the specified name and path. +func imports(f *ast.File, name, path string) bool { + for _, s := range f.Imports { + if importName(s) == name && importPath(s) == path { + return true + } + } + return false } // importSpec returns the import spec if f imports path, @@ -399,14 +400,23 @@ func importSpec(f *ast.File, path string) *ast.ImportSpec { return nil } +// importName returns the name of s, +// or "" if the import is not named. +func importName(s *ast.ImportSpec) string { + if s.Name == nil { + return "" + } + return s.Name.Name +} + // importPath returns the unquoted import path of s, // or "" if the path is not properly quoted. func importPath(s *ast.ImportSpec) string { t, err := strconv.Unquote(s.Path.Value) - if err == nil { - return t + if err != nil { + return "" } - return "" + return t } // declImports reports whether gen contains an import of path. diff --git a/src/cmd/vendor/update-xtools.sh b/src/cmd/vendor/update-xtools.sh new file mode 100755 index 00000000000000..8cf5ac165df4aa --- /dev/null +++ b/src/cmd/vendor/update-xtools.sh @@ -0,0 +1,31 @@ +#!/bin/sh +# +# update-xtools.sh: idempotently update the vendored +# copy of the x/tools repository used by cmd/vet. + +set -u + +analysis=$(go list -f {{.Dir}} golang.org/x/tools/go/analysis) || + { echo "Add golang.org/x/tools to your GOPATH"; exit 1; } >&2 +xtools=$(dirname $(dirname $analysis)) + +vendor=$(dirname $0) + +# Find the x/tools packages directly imported by cmd/vet. +go list -f '{{range $k, $v := .ImportMap}}{{$k}} {{end}}' cmd/vet | + grep golang.org/x/tools | + # Vendor their transitive closure of dependencies. + xargs go list -f '{{.ImportPath}} {{.Dir}}' -deps | + grep golang.org/x/tools | + while read path dir + do + mkdir -p $vendor/$path + cp $dir/* -t $vendor/$path 2>/dev/null # ignore errors from subdirectories + rm -f $vendor/$path/*_test.go + git add $vendor/$path + done + +echo "Copied $xtools@$(cd $analysis && git rev-parse --short HEAD) to $vendor" >&2 + +go build -o /dev/null cmd/vet || + { echo "Failed to build cmd/vet"; exit 1; } >&2 diff --git a/src/cmd/vet/all/main.go b/src/cmd/vet/all/main.go index 7e4a68101f0457..2500c690bfd6eb 100644 --- a/src/cmd/vet/all/main.go +++ b/src/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" @@ -217,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() @@ -243,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 } @@ -254,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/src/cmd/vet/all/whitelist/386.txt b/src/cmd/vet/all/whitelist/386.txt index 3dbb340cbd6d19..f791a265701751 100644 --- a/src/cmd/vet/all/whitelist/386.txt +++ b/src/cmd/vet/all/whitelist/386.txt @@ -1,7 +1,5 @@ // 386-specific vet whitelist. See readme.txt for details. -internal/bytealg/compare_386.s: [386] cannot check cross-package assembly function: cmpstring is in package runtime - // startup code uses non-standard calling convention and intentionally // omits args. runtime/asm_386.s: [386] rt0_go: use of 4(SP) points beyond argument frame diff --git a/src/cmd/vet/all/whitelist/all.txt b/src/cmd/vet/all/whitelist/all.txt index 38caac3c3b3565..c73516392f6bf1 100644 --- a/src/cmd/vet/all/whitelist/all.txt +++ b/src/cmd/vet/all/whitelist/all.txt @@ -9,10 +9,6 @@ go/types/scope.go: method WriteTo(w io.Writer, n int, recurse bool) should have // False positives. -// Nothing much to do about cross-package assembly. Unfortunate. -internal/bytealg/equal_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: memequal is in package runtime -internal/bytealg/equal_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: memequal_varlen is in package runtime - // The write barrier is called directly by the compiler, so no Go def runtime/asm_ARCHSUFF.s: [GOARCH] gcWriteBarrier: function gcWriteBarrier missing Go declaration @@ -22,8 +18,6 @@ encoding/json/decode_test.go: struct field m has json tag but is not exported encoding/json/decode_test.go: struct field m2 has json tag but is not exported encoding/json/decode_test.go: struct field s has json tag but is not exported encoding/json/tagkey_test.go: struct field tag `:"BadFormat"` not compatible with reflect.StructTag.Get: bad syntax for struct tag key -runtime/testdata/testprog/deadlock.go: unreachable code -runtime/testdata/testprog/deadlock.go: unreachable code // Compiler tests that make sure even vet-failing code adheres to the spec. cmd/compile/internal/gc/testdata/arithConst_test.go: a (64 bits) too small for shift of 4294967296 @@ -68,3 +62,7 @@ cmd/link/link_test.go: struct field tag "\n\tLondon. Michaelmas term lately over cmd/link/link_test.go: struct field tag "\n\tIt was grand to see how the wind awoke, and bent the trees, and drove the rain before it like a cloud of smoke; and to hear the solemn thunder, and to see the lightning; and while thinking with awe of the tremendous powers by which our little lives are encompassed, to consider how beneficent they are, and how upon the smallest flower and leaf there was already a freshness poured from all this seeming rage, which seemed to make creation new again." not compatible with reflect.StructTag.Get: bad syntax for struct tag key cmd/link/link_test.go: struct field tag "\n\tJarndyce and Jarndyce drones on. This scarecrow of a suit has, over the course of time, become so complicated, that no man alive knows what it means. The parties to it understand it least; but it has been observed that no two Chancery lawyers can talk about it for five minutes, without coming to a total disagreement as to all the premises. Innumerable children have been born into the cause; innumerable young people have married into it; innumerable old people have died out of it. Scores of persons have deliriously found themselves made parties in Jarndyce and Jarndyce, without knowing how or why; whole families have inherited legendary hatreds with the suit. The little plaintiff or defendant, who was promised a new rocking-horse when Jarndyce and Jarndyce should be settled, has grown up, possessed himself of a real horse, and trotted away into the other world. Fair wards of court have faded into mothers and grandmothers; a long procession of Chancellors has come in and gone out; the legion of bills in the suit have been transformed into mere bills of mortality; there are not three Jarndyces left upon the earth perhaps, since old Tom Jarndyce in despair blew his brains out at a coffee-house in Chancery Lane; but Jarndyce and Jarndyce still drags its dreary length before the Court, perennially hopeless." not compatible with reflect.StructTag.Get: bad syntax for struct tag key cmd/link/link_test.go: struct field tag "\n\tThe one great principle of the English law is, to make business for itself. There is no other principle distinctly, certainly, and consistently maintained through all its narrow turnings. Viewed by this light it becomes a coherent scheme, and not the monstrous maze the laity are apt to think it. Let them but once clearly perceive that its grand principle is to make business for itself at their expense, and surely they will cease to grumble." not compatible with reflect.StructTag.Get: bad syntax for struct tag key + +// Tests of Decode(nil) trigger legitimate diagnostics. +encoding/gob/encoder_test.go: call of Decode passes non-pointer +encoding/gob/encoder_test.go: call of Decode passes non-pointer diff --git a/src/cmd/vet/all/whitelist/amd64.txt b/src/cmd/vet/all/whitelist/amd64.txt index 94f782aa2fd2a7..020241f615a50f 100644 --- a/src/cmd/vet/all/whitelist/amd64.txt +++ b/src/cmd/vet/all/whitelist/amd64.txt @@ -2,9 +2,6 @@ // False positives. -// Nothing much to do about cross-package assembly. Unfortunate. -internal/bytealg/compare_amd64.s: [amd64] cannot check cross-package assembly function: cmpstring is in package runtime - // reflect trampolines intentionally omit arg size. Same for morestack. runtime/asm_amd64.s: [amd64] morestack: use of 8(SP) points beyond argument frame runtime/asm_amd64.s: [amd64] morestack: use of 16(SP) points beyond argument frame diff --git a/src/cmd/vet/all/whitelist/arm.txt b/src/cmd/vet/all/whitelist/arm.txt index 5dc2766e10d301..81a1f1831ea8f3 100644 --- a/src/cmd/vet/all/whitelist/arm.txt +++ b/src/cmd/vet/all/whitelist/arm.txt @@ -1,7 +1,5 @@ // arm-specific vet whitelist. See readme.txt for details. -internal/bytealg/compare_arm.s: [arm] cannot check cross-package assembly function: cmpstring is in package runtime - // Intentionally missing declarations. runtime/asm_arm.s: [arm] emptyfunc: function emptyfunc missing Go declaration runtime/asm_arm.s: [arm] armPublicationBarrier: function armPublicationBarrier missing Go declaration diff --git a/src/cmd/vet/all/whitelist/arm64.txt b/src/cmd/vet/all/whitelist/arm64.txt index 72528c5145a379..5a0af626f6aea4 100644 --- a/src/cmd/vet/all/whitelist/arm64.txt +++ b/src/cmd/vet/all/whitelist/arm64.txt @@ -1,7 +1,5 @@ // arm64-specific vet whitelist. See readme.txt for details. -internal/bytealg/compare_arm64.s: [arm64] cannot check cross-package assembly function: cmpstring is in package runtime - // Intentionally missing declarations. runtime/asm_arm64.s: [arm64] addmoduledata: function addmoduledata missing Go declaration runtime/duff_arm64.s: [arm64] duffzero: function duffzero missing Go declaration diff --git a/src/cmd/vet/all/whitelist/mipsx.txt b/src/cmd/vet/all/whitelist/mipsx.txt index bd53e9acdf853c..1451a86e28c629 100644 --- a/src/cmd/vet/all/whitelist/mipsx.txt +++ b/src/cmd/vet/all/whitelist/mipsx.txt @@ -1,7 +1,5 @@ // mips/mipsle-specific vet whitelist. See readme.txt for details. -internal/bytealg/compare_mipsx.s: [GOARCH] cannot check cross-package assembly function: cmpstring is in package runtime - runtime/tls_mipsx.s: [GOARCH] save_g: function save_g missing Go declaration runtime/tls_mipsx.s: [GOARCH] load_g: function load_g missing Go declaration runtime/sys_linux_mipsx.s: [GOARCH] clone: 12(R29) should be mp+8(FP) diff --git a/src/cmd/vet/all/whitelist/nacl_386.txt b/src/cmd/vet/all/whitelist/nacl_386.txt index 68bba518ac6739..c4b03e40936fe8 100644 --- a/src/cmd/vet/all/whitelist/nacl_386.txt +++ b/src/cmd/vet/all/whitelist/nacl_386.txt @@ -1,7 +1,5 @@ // nacl/386-specific vet whitelist. See readme.txt for details. -runtime/sys_nacl_386.s: [386] cannot check cross-package assembly function: naclWrite is in package syscall -runtime/sys_nacl_386.s: [386] cannot check cross-package assembly function: now is in package syscall runtime/sys_nacl_386.s: [386] nacl_clock_gettime: function nacl_clock_gettime missing Go declaration runtime/sys_nacl_386.s: [386] setldt: function setldt missing Go declaration runtime/sys_nacl_386.s: [386] sigtramp: use of 20(SP) points beyond argument frame diff --git a/src/cmd/vet/all/whitelist/nacl_amd64p32.txt b/src/cmd/vet/all/whitelist/nacl_amd64p32.txt index 5625e3c55d0b46..9661f57b23d9c2 100644 --- a/src/cmd/vet/all/whitelist/nacl_amd64p32.txt +++ b/src/cmd/vet/all/whitelist/nacl_amd64p32.txt @@ -1,7 +1,5 @@ // nacl/amd64p32-specific vet whitelist. See readme.txt for details. -internal/bytealg/compare_amd64p32.s: [amd64p32] cannot check cross-package assembly function: cmpstring is in package runtime - // reflect trampolines intentionally omit arg size. Same for morestack. runtime/asm_amd64p32.s: [amd64p32] morestack: use of 8(SP) points beyond argument frame runtime/asm_amd64p32.s: [amd64p32] morestack: use of 16(SP) points beyond argument frame @@ -13,8 +11,6 @@ runtime/sys_nacl_amd64p32.s: [amd64p32] sigtramp: unknown variable ctxt runtime/sys_nacl_amd64p32.s: [amd64p32] sigtramp: unknown variable ctxt runtime/sys_nacl_amd64p32.s: [amd64p32] sigtramp: unknown variable ctxt runtime/sys_nacl_amd64p32.s: [amd64p32] nacl_sysinfo: function nacl_sysinfo missing Go declaration -runtime/sys_nacl_amd64p32.s: [amd64p32] cannot check cross-package assembly function: naclWrite is in package syscall -runtime/sys_nacl_amd64p32.s: [amd64p32] cannot check cross-package assembly function: now is in package syscall runtime/sys_nacl_amd64p32.s: [amd64p32] nacl_clock_gettime: function nacl_clock_gettime missing Go declaration runtime/sys_nacl_amd64p32.s: [amd64p32] settls: function settls missing Go declaration diff --git a/src/cmd/vet/all/whitelist/nacl_arm.txt b/src/cmd/vet/all/whitelist/nacl_arm.txt index cc0fcbab7f2fe9..dde0092570234f 100644 --- a/src/cmd/vet/all/whitelist/nacl_arm.txt +++ b/src/cmd/vet/all/whitelist/nacl_arm.txt @@ -1,8 +1,6 @@ // nacl/arm-specific vet whitelist. See readme.txt for details. runtime/asm_arm.s: [arm] sigreturn: function sigreturn missing Go declaration -runtime/sys_nacl_arm.s: [arm] cannot check cross-package assembly function: naclWrite is in package syscall -runtime/sys_nacl_arm.s: [arm] cannot check cross-package assembly function: now is in package syscall runtime/sys_nacl_arm.s: [arm] nacl_clock_gettime: function nacl_clock_gettime missing Go declaration runtime/sys_nacl_arm.s: [arm] nacl_sysinfo: function nacl_sysinfo missing Go declaration runtime/sys_nacl_arm.s: [arm] read_tls_fallback: function read_tls_fallback missing Go declaration diff --git a/src/cmd/vet/all/whitelist/ppc64x.txt b/src/cmd/vet/all/whitelist/ppc64x.txt index 39f8c0da31adbe..730a753afc2e0d 100644 --- a/src/cmd/vet/all/whitelist/ppc64x.txt +++ b/src/cmd/vet/all/whitelist/ppc64x.txt @@ -1,7 +1,5 @@ // ppc64-specific vet whitelist. See readme.txt for details. -internal/bytealg/compare_ppc64x.s: [GOARCH] cannot check cross-package assembly function: cmpstring is in package runtime - runtime/asm_ppc64x.s: [GOARCH] reginit: function reginit missing Go declaration runtime/asm_ppc64x.s: [GOARCH] goexit: use of 24(R1) points beyond argument frame runtime/asm_ppc64x.s: [GOARCH] addmoduledata: function addmoduledata missing Go declaration diff --git a/src/cmd/vet/all/whitelist/s390x.txt b/src/cmd/vet/all/whitelist/s390x.txt index 4b842420382125..55cf44a5198bc6 100644 --- a/src/cmd/vet/all/whitelist/s390x.txt +++ b/src/cmd/vet/all/whitelist/s390x.txt @@ -1,13 +1,12 @@ -internal/bytealg/compare_s390x.s: [s390x] cannot check cross-package assembly function: cmpstring is in package runtime runtime/asm_s390x.s: [s390x] addmoduledata: function addmoduledata missing Go declaration runtime/memclr_s390x.s: [s390x] memclr_s390x_exrl_xc: function memclr_s390x_exrl_xc missing Go declaration runtime/memmove_s390x.s: [s390x] memmove_s390x_exrl_mvc: function memmove_s390x_exrl_mvc missing Go declaration runtime/tls_s390x.s: [s390x] save_g: function save_g missing Go declaration runtime/tls_s390x.s: [s390x] load_g: function load_g missing Go declaration -internal/cpu/cpu_s390x.s: [s390x] stfle: invalid MOVD of ret+0(FP); cpu.facilityList is 32-byte value -internal/cpu/cpu_s390x.s: [s390x] kmQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value -internal/cpu/cpu_s390x.s: [s390x] kmcQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value -internal/cpu/cpu_s390x.s: [s390x] kmctrQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value -internal/cpu/cpu_s390x.s: [s390x] kmaQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value -internal/cpu/cpu_s390x.s: [s390x] kimdQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value -internal/cpu/cpu_s390x.s: [s390x] klmdQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value +internal/cpu/cpu_s390x.s: [s390x] stfle: invalid MOVD of ret+0(FP); internal/cpu.facilityList is 32-byte value +internal/cpu/cpu_s390x.s: [s390x] kmQuery: invalid MOVD of ret+0(FP); internal/cpu.queryResult is 16-byte value +internal/cpu/cpu_s390x.s: [s390x] kmcQuery: invalid MOVD of ret+0(FP); internal/cpu.queryResult is 16-byte value +internal/cpu/cpu_s390x.s: [s390x] kmctrQuery: invalid MOVD of ret+0(FP); internal/cpu.queryResult is 16-byte value +internal/cpu/cpu_s390x.s: [s390x] kmaQuery: invalid MOVD of ret+0(FP); internal/cpu.queryResult is 16-byte value +internal/cpu/cpu_s390x.s: [s390x] kimdQuery: invalid MOVD of ret+0(FP); internal/cpu.queryResult is 16-byte value +internal/cpu/cpu_s390x.s: [s390x] klmdQuery: invalid MOVD of ret+0(FP); internal/cpu.queryResult is 16-byte value diff --git a/src/cmd/vet/all/whitelist/wasm.txt b/src/cmd/vet/all/whitelist/wasm.txt index d066e5b76f8f02..a3f8c291bf9e23 100644 --- a/src/cmd/vet/all/whitelist/wasm.txt +++ b/src/cmd/vet/all/whitelist/wasm.txt @@ -2,9 +2,6 @@ // False positives. -// Nothing much to do about cross-package assembly. Unfortunate. -internal/bytealg/compare_wasm.s: [wasm] cannot check cross-package assembly function: cmpstring is in package runtime - // morestack intentionally omits arg size. runtime/asm_wasm.s: [wasm] morestack: use of 8(SP) points beyond argument frame runtime/asm_wasm.s: [wasm] morestack: use of 16(SP) points beyond argument frame diff --git a/src/cmd/vet/all/whitelist/windows_386.txt b/src/cmd/vet/all/whitelist/windows_386.txt index d910022ef655ea..87b3b24d7f70d3 100644 --- a/src/cmd/vet/all/whitelist/windows_386.txt +++ b/src/cmd/vet/all/whitelist/windows_386.txt @@ -6,4 +6,3 @@ runtime/sys_windows_386.s: [386] setldt: function setldt missing Go declaration runtime/sys_windows_386.s: [386] callbackasm1+0: function callbackasm1+0 missing Go declaration runtime/sys_windows_386.s: [386] tstart: function tstart missing Go declaration runtime/sys_windows_386.s: [386] tstart_stdcall: RET without writing to 4-byte ret+4(FP) -runtime/sys_windows_386.s: [386] cannot check cross-package assembly function: now is in package time diff --git a/src/cmd/vet/all/whitelist/windows_amd64.txt b/src/cmd/vet/all/whitelist/windows_amd64.txt index 676e6baf71b79a..daa23e73a15fdd 100644 --- a/src/cmd/vet/all/whitelist/windows_amd64.txt +++ b/src/cmd/vet/all/whitelist/windows_amd64.txt @@ -5,4 +5,3 @@ runtime/sys_windows_amd64.s: [amd64] ctrlhandler: RET without writing to 4-byte runtime/sys_windows_amd64.s: [amd64] callbackasm1: function callbackasm1 missing Go declaration runtime/sys_windows_amd64.s: [amd64] tstart_stdcall: RET without writing to 4-byte ret+8(FP) runtime/sys_windows_amd64.s: [amd64] settls: function settls missing Go declaration -runtime/sys_windows_amd64.s: [amd64] cannot check cross-package assembly function: now is in package time diff --git a/src/cmd/vet/asmdecl.go b/src/cmd/vet/asmdecl.go deleted file mode 100644 index ccf6269f1db292..00000000000000 --- a/src/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/src/cmd/vet/assign.go b/src/cmd/vet/assign.go deleted file mode 100644 index 223e80d400710b..00000000000000 --- a/src/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 " = ". -// 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/src/cmd/vet/atomic.go b/src/cmd/vet/atomic.go deleted file mode 100644 index b425669e1ae057..00000000000000 --- a/src/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/src/cmd/vet/bool.go b/src/cmd/vet/bool.go deleted file mode 100644 index 1cd477f988caf0..00000000000000 --- a/src/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/src/cmd/vet/buildtag.go b/src/cmd/vet/buildtag.go deleted file mode 100644 index ba3a361b9113bb..00000000000000 --- a/src/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/src/cmd/vet/cgo.go b/src/cmd/vet/cgo.go deleted file mode 100644 index 76364ff6ed8bec..00000000000000 --- a/src/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/src/cmd/vet/composite.go b/src/cmd/vet/composite.go deleted file mode 100644 index 861e040aac4e52..00000000000000 --- a/src/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/src/cmd/vet/copylock.go b/src/cmd/vet/copylock.go deleted file mode 100644 index ed88ca89603a43..00000000000000 --- a/src/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/src/cmd/vet/dead.go b/src/cmd/vet/dead.go deleted file mode 100644 index 0facec552583a0..00000000000000 --- a/src/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/src/cmd/vet/deadcode.go b/src/cmd/vet/deadcode.go deleted file mode 100644 index b1077aef38fdc4..00000000000000 --- a/src/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/src/cmd/vet/doc.go b/src/cmd/vet/doc.go index d9af0a88759a33..279d081be39c93 100644 --- a/src/cmd/vet/doc.go +++ b/src/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/src/cmd/vet/httpresponse.go b/src/cmd/vet/httpresponse.go deleted file mode 100644 index 791d11d5bdef04..00000000000000 --- a/src/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/src/cmd/vet/internal/cfg/builder.go b/src/cmd/vet/internal/cfg/builder.go deleted file mode 100644 index da1cc7e6384df2..00000000000000 --- a/src/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/src/cmd/vet/internal/cfg/cfg.go b/src/cmd/vet/internal/cfg/cfg.go deleted file mode 100644 index e4d5bfe5d2d3b8..00000000000000 --- a/src/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/src/cmd/vet/internal/cfg/cfg_test.go b/src/cmd/vet/internal/cfg/cfg_test.go deleted file mode 100644 index 2400fed6f4b2fc..00000000000000 --- a/src/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/src/cmd/vet/internal/whitelist/whitelist.go b/src/cmd/vet/internal/whitelist/whitelist.go deleted file mode 100644 index fdd65d373233e5..00000000000000 --- a/src/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/src/cmd/vet/lostcancel.go b/src/cmd/vet/lostcancel.go deleted file mode 100644 index ee0342035fe372..00000000000000 --- a/src/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/src/cmd/vet/main.go b/src/cmd/vet/main.go index 799f0bfb643293..4ec174b3cd1e06 100644 --- a/src/cmd/vet/main.go +++ b/src/cmd/vet/main.go @@ -1,783 +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" - "log" - "os" - "path/filepath" - "sort" - "strconv" - "strings" - - "cmd/internal/objabi" -) - -var ( - verbose = flag.Bool("v", false, "verbose") - flags = flag.Bool("flags", false, "print flags in JSON") - 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 + "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" ) -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{}) -) - -// 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() - - // -flags: print flags as JSON. Used by go vet. - if *flags { - type jsonFlag struct { - Name string - Bool bool - Usage string - } - var jsonFlags []jsonFlag - flag.VisitAll(func(f *flag.Flag) { - isBool := false - switch v := f.Value.(type) { - case interface{ BoolFlag() bool }: - isBool = v.BoolFlag() - case *triState: - isBool = true // go vet should treat it as boolean - } - jsonFlags = append(jsonFlags, jsonFlag{f.Name, isBool, f.Usage}) - }) - data, err := json.MarshalIndent(jsonFlags, "", "\t") - if err != nil { - log.Fatal(err) - } - os.Stdout.Write(data) - os.Exit(0) - } - - // 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.ReplaceAll(*tags, ",", " ")) - - 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 - NonGoFiles []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 - - var allFiles []string - allFiles = append(allFiles, vcfg.GoFiles...) - allFiles = append(allFiles, vcfg.NonGoFiles...) - - doPackage(allFiles, 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 - implicits map[ast.Node]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/src/cmd/vet/method.go b/src/cmd/vet/method.go deleted file mode 100644 index 8b404e069782ac..00000000000000 --- a/src/cmd/vet/method.go +++ /dev/null @@ -1,150 +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 ( - "go/ast" - "go/types" - "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) - } - case *ast.InterfaceType: - for _, field := range n.Methods.List { - for _, id := range field.Names { - canonicalMethod(f, id) - } - } - } -} - -func canonicalMethod(f *File, id *ast.Ident) { - // Expected input/output. - expect, ok := canonicalMethods[id.Name] - if !ok { - return - } - sign := f.pkg.defs[id].Type().(*types.Signature) - args := sign.Params() - results := sign.Results() - - // 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) + ")" - } - - actual := sign.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, ", ") -} - -// Does each type in expect with the given prefix match the corresponding type in actual? -func (f *File) matchParams(expect []string, actual *types.Tuple, prefix string) bool { - for i, x := range expect { - if !strings.HasPrefix(x, prefix) { - continue - } - if i >= actual.Len() { - return false - } - if !f.matchParamType(x, actual.At(i).Type()) { - return false - } - } - if prefix == "" && actual.Len() > len(expect) { - return false - } - return true -} - -// Does this one type match? -func (f *File) matchParamType(expect string, actual types.Type) 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. - return actual.String() == expect -} diff --git a/src/cmd/vet/nilfunc.go b/src/cmd/vet/nilfunc.go deleted file mode 100644 index bfe05e3353da9a..00000000000000 --- a/src/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/src/cmd/vet/print.go b/src/cmd/vet/print.go deleted file mode 100644 index 3a2eea0beba55d..00000000000000 --- a/src/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 reports whether 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/src/cmd/vet/rangeloop.go b/src/cmd/vet/rangeloop.go deleted file mode 100644 index 53a41364dfe1b8..00000000000000 --- a/src/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/src/cmd/vet/shadow.go b/src/cmd/vet/shadow.go deleted file mode 100644 index 47a48834bfcc07..00000000000000 --- a/src/cmd/vet/shadow.go +++ /dev/null @@ -1,243 +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 source range [pos, end). -func (pkg *Package) growSpan(obj types.Object, pos, end token.Pos) { - if *strictShadowing { - return // No need - } - 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(shadowed.Pos(), "internal error: no range for %q", shadowed.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/src/cmd/vet/shift.go b/src/cmd/vet/shift.go deleted file mode 100644 index 1e48d325242bde..00000000000000 --- a/src/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/src/cmd/vet/structtag.go b/src/cmd/vet/structtag.go deleted file mode 100644 index 32366eab44bac5..00000000000000 --- a/src/cmd/vet/structtag.go +++ /dev/null @@ -1,241 +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" - "go/types" - "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) { - astType := node.(*ast.StructType) - typ := f.pkg.types[astType].Type.(*types.Struct) - var seen map[[2]string]token.Pos - for i := 0; i < typ.NumFields(); i++ { - field := typ.Field(i) - tag := typ.Tag(i) - checkCanonicalFieldTag(f, astType, field, tag, &seen) - } -} - -var checkTagDups = []string{"json", "xml"} -var checkTagSpaces = map[string]bool{"json": true, "xml": true, "asn1": true} - -// checkCanonicalFieldTag checks a single struct field tag. -// top is the top-level struct type that is currently being checked. -func checkCanonicalFieldTag(f *File, top *ast.StructType, field *types.Var, tag string, seen *map[[2]string]token.Pos) { - for _, key := range checkTagDups { - checkTagDuplicates(f, tag, key, field, field, seen) - } - - if err := validateStructTag(tag); err != nil { - f.Badf(field.Pos(), "struct field tag %#q not compatible with reflect.StructTag.Get: %s", tag, err) - } - - // 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 field.Anonymous() { - return - } - - if field.Exported() { - 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.Name(), enc) - return - } - } -} - -// checkTagDuplicates checks a single struct field tag to see if any tags are -// duplicated. nearest is the field that's closest to the field being checked, -// while still being part of the top-level struct type. -func checkTagDuplicates(f *File, tag, key string, nearest, field *types.Var, seen *map[[2]string]token.Pos) { - val := reflect.StructTag(tag).Get(key) - if val == "-" { - // Ignored, even if the field is anonymous. - return - } - if val == "" || val[0] == ',' { - if field.Anonymous() { - typ, ok := field.Type().Underlying().(*types.Struct) - if !ok { - return - } - for i := 0; i < typ.NumFields(); i++ { - field := typ.Field(i) - if !field.Exported() { - continue - } - tag := typ.Tag(i) - checkTagDuplicates(f, tag, key, nearest, field, seen) - } - } - // Ignored if the field isn't anonymous. - return - } - if key == "xml" && field.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. - return - } - 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 { - f.Badf(nearest.Pos(), "struct field %s repeats %s tag %q also at %s", field.Name(), key, val, f.loc(pos)) - } else { - (*seen)[[2]string{key, val}] = field.Pos() - } -} - -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/src/cmd/vet/testdata/asm/asm.go b/src/cmd/vet/testdata/asm/asm.go deleted file mode 100644 index 2237ddc3b05c93..00000000000000 --- a/src/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/src/cmd/vet/testdata/asm/asm1.s b/src/cmd/vet/testdata/asm/asm1.s deleted file mode 100644 index cac6ed22cd0031..00000000000000 --- a/src/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/src/cmd/vet/testdata/asm/asm2.s b/src/cmd/vet/testdata/asm/asm2.s deleted file mode 100644 index c33c02a70b27e3..00000000000000 --- a/src/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/src/cmd/vet/testdata/asm/asm3.s b/src/cmd/vet/testdata/asm/asm3.s deleted file mode 100644 index 83e53862d7d1b6..00000000000000 --- a/src/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/src/cmd/vet/testdata/asm/asm4.s b/src/cmd/vet/testdata/asm/asm4.s deleted file mode 100644 index 044b050b6b99e1..00000000000000 --- a/src/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/src/cmd/vet/testdata/asm/asm5.s b/src/cmd/vet/testdata/asm/asm5.s deleted file mode 100644 index c6176e9669f572..00000000000000 --- a/src/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/src/cmd/vet/testdata/asm/asm6.s b/src/cmd/vet/testdata/asm/asm6.s deleted file mode 100644 index 4e85ab3dcf9677..00000000000000 --- a/src/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/src/cmd/vet/testdata/asm/asm7.s b/src/cmd/vet/testdata/asm/asm7.s deleted file mode 100644 index d5ff5460a565d7..00000000000000 --- a/src/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/src/cmd/vet/testdata/asm8.s b/src/cmd/vet/testdata/asm8.s deleted file mode 100644 index 550d92a8d2daa6..00000000000000 --- a/src/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/src/cmd/vet/testdata/atomic.go b/src/cmd/vet/testdata/atomic.go deleted file mode 100644 index 69730b4e6f03fb..00000000000000 --- a/src/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/src/cmd/vet/testdata/bool.go b/src/cmd/vet/testdata/bool.go deleted file mode 100644 index 80c44d25ca3889..00000000000000 --- a/src/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/src/cmd/vet/testdata/buildtag/buildtag_bad.go b/src/cmd/vet/testdata/buildtag/buildtag_bad.go deleted file mode 100644 index fbe10cf748f58b..00000000000000 --- a/src/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/src/cmd/vet/testdata/cgo/cgo.go b/src/cmd/vet/testdata/cgo/cgo.go deleted file mode 100644 index d0df7cf6787fe0..00000000000000 --- a/src/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/src/cmd/vet/testdata/cgo/cgo2.go b/src/cmd/vet/testdata/cgo/cgo2.go deleted file mode 100644 index 4f271168931383..00000000000000 --- a/src/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/src/cmd/vet/testdata/cgo/cgo3.go b/src/cmd/vet/testdata/cgo/cgo3.go deleted file mode 100644 index 0b1518e1f930a5..00000000000000 --- a/src/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/src/cmd/vet/testdata/cgo/cgo4.go b/src/cmd/vet/testdata/cgo/cgo4.go deleted file mode 100644 index 67b54506abae1a..00000000000000 --- a/src/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/src/cmd/vet/testdata/composite.go b/src/cmd/vet/testdata/composite.go deleted file mode 100644 index 3fe3eac78cb38a..00000000000000 --- a/src/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/src/cmd/vet/testdata/copylock.go b/src/cmd/vet/testdata/copylock.go deleted file mode 100644 index e9902a27f10dd2..00000000000000 --- a/src/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/src/cmd/vet/testdata/copylock_func.go b/src/cmd/vet/testdata/copylock_func.go deleted file mode 100644 index 280747a3bf46d3..00000000000000 --- a/src/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/src/cmd/vet/testdata/copylock_range.go b/src/cmd/vet/testdata/copylock_range.go deleted file mode 100644 index f127381213cd75..00000000000000 --- a/src/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/src/cmd/vet/testdata/deadcode.go b/src/cmd/vet/testdata/deadcode.go deleted file mode 100644 index d1a7adee38d2c9..00000000000000 --- a/src/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/src/cmd/vet/testdata/divergent/buf.go b/src/cmd/vet/testdata/divergent/buf.go deleted file mode 100644 index 0efe0f838d56ee..00000000000000 --- a/src/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/src/cmd/vet/testdata/divergent/buf_test.go b/src/cmd/vet/testdata/divergent/buf_test.go deleted file mode 100644 index b75d55eaf4f2dd..00000000000000 --- a/src/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/src/cmd/vet/testdata/httpresponse.go b/src/cmd/vet/testdata/httpresponse.go deleted file mode 100644 index 7302a64a3b6a59..00000000000000 --- a/src/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/src/cmd/vet/testdata/incomplete/examples_test.go b/src/cmd/vet/testdata/incomplete/examples_test.go deleted file mode 100644 index 445502b39ecdef..00000000000000 --- a/src/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/src/cmd/vet/testdata/lostcancel.go b/src/cmd/vet/testdata/lostcancel.go deleted file mode 100644 index b7549c00511127..00000000000000 --- a/src/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/src/cmd/vet/testdata/nilfunc.go b/src/cmd/vet/testdata/nilfunc.go deleted file mode 100644 index 2ce7bc8ca82ecc..00000000000000 --- a/src/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/src/cmd/vet/testdata/rangeloop.go b/src/cmd/vet/testdata/rangeloop.go deleted file mode 100644 index cd3b4cbc452231..00000000000000 --- a/src/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/src/cmd/vet/testdata/shadow.go b/src/cmd/vet/testdata/shadow.go deleted file mode 100644 index d10fde2b811d03..00000000000000 --- a/src/cmd/vet/testdata/shadow.go +++ /dev/null @@ -1,91 +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 -} - -// Must not complain with an internal error for the -// implicitly declared type switch variable v. -func issue26725(x interface{}) int { - switch v := x.(type) { - case int, int32: - if v, ok := x.(int); ok { - return v - } - case int64: - return int(v) - } - return 0 -} - -// Verify that implicitly declared variables from -// type switches are considered in shadowing analysis. -func shadowTypeSwitch(a interface{}) { - switch t := a.(type) { - case int: - { - t := 0 // ERROR "declaration of .t. shadows declaration at shadow.go:78" - _ = t - } - _ = t - case uint: - { - t := uint(0) // OK because t is not mentioned later in this function - _ = t - } - } -} diff --git a/src/cmd/vet/testdata/shift.go b/src/cmd/vet/testdata/shift.go deleted file mode 100644 index 73cbaf884180c6..00000000000000 --- a/src/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/src/cmd/vet/testdata/src/asm/asm.go b/src/cmd/vet/testdata/src/asm/asm.go new file mode 100644 index 00000000000000..72ff452aae8445 --- /dev/null +++ b/src/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/src/cmd/vet/testdata/src/asm/asm1.s b/src/cmd/vet/testdata/src/asm/asm1.s new file mode 100644 index 00000000000000..c3ba986fb8b121 --- /dev/null +++ b/src/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/src/cmd/vet/testdata/assign.go b/src/cmd/vet/testdata/src/assign/assign.go similarity index 97% rename from src/cmd/vet/testdata/assign.go rename to src/cmd/vet/testdata/src/assign/assign.go index 6140ad4db8cc0c..112614e562c683 100644 --- a/src/cmd/vet/testdata/assign.go +++ b/src/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/src/cmd/vet/testdata/src/atomic/atomic.go b/src/cmd/vet/testdata/src/atomic/atomic.go new file mode 100644 index 00000000000000..650d56bdadaef7 --- /dev/null +++ b/src/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/src/cmd/vet/testdata/src/bool/bool.go b/src/cmd/vet/testdata/src/bool/bool.go new file mode 100644 index 00000000000000..20e01aa46f091b --- /dev/null +++ b/src/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/src/cmd/vet/testdata/buildtag/buildtag.go b/src/cmd/vet/testdata/src/buildtag/buildtag.go similarity index 100% rename from src/cmd/vet/testdata/buildtag/buildtag.go rename to src/cmd/vet/testdata/src/buildtag/buildtag.go diff --git a/src/cmd/vet/testdata/src/cgo/cgo.go b/src/cmd/vet/testdata/src/cgo/cgo.go new file mode 100644 index 00000000000000..292d7fdab7dff4 --- /dev/null +++ b/src/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/src/cmd/vet/testdata/src/composite/composite.go b/src/cmd/vet/testdata/src/composite/composite.go new file mode 100644 index 00000000000000..63a28378515cc2 --- /dev/null +++ b/src/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/src/cmd/vet/testdata/src/copylock/copylock.go b/src/cmd/vet/testdata/src/copylock/copylock.go new file mode 100644 index 00000000000000..8079cf3248b785 --- /dev/null +++ b/src/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/src/cmd/vet/testdata/src/deadcode/deadcode.go b/src/cmd/vet/testdata/src/deadcode/deadcode.go new file mode 100644 index 00000000000000..af83cdfbb1e82d --- /dev/null +++ b/src/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/src/cmd/vet/testdata/src/httpresponse/httpresponse.go b/src/cmd/vet/testdata/src/httpresponse/httpresponse.go new file mode 100644 index 00000000000000..6141f6e06dce69 --- /dev/null +++ b/src/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/src/cmd/vet/testdata/src/lostcancel/lostcancel.go b/src/cmd/vet/testdata/src/lostcancel/lostcancel.go new file mode 100644 index 00000000000000..1bbb22d27b4b3f --- /dev/null +++ b/src/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/src/cmd/vet/testdata/method.go b/src/cmd/vet/testdata/src/method/method.go similarity index 62% rename from src/cmd/vet/testdata/method.go rename to src/cmd/vet/testdata/src/method/method.go index 978527d09089b2..51c3f65fcc728e 100644 --- a/src/cmd/vet/testdata/method.go +++ b/src/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\(fmt\.ScanState, rune\) error" } - -type MethodTestInterface interface { - ReadByte() byte // ERROR "should have signature ReadByte\(\) \(byte, error\)" -} diff --git a/src/cmd/vet/testdata/src/nilfunc/nilfunc.go b/src/cmd/vet/testdata/src/nilfunc/nilfunc.go new file mode 100644 index 00000000000000..c34d60e05214cf --- /dev/null +++ b/src/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/src/cmd/vet/testdata/print.go b/src/cmd/vet/testdata/src/print/print.go similarity index 94% rename from src/cmd/vet/testdata/print.go rename to src/cmd/vet/testdata/src/print/print.go index 994902d01dad7f..6bacd0fd747c86 100644 --- a/src/cmd/vet/testdata/print.go +++ b/src/cmd/vet/testdata/src/print/print.go @@ -4,7 +4,7 @@ // This file contains tests for the printf checker. -package testdata +package print import ( "fmt" @@ -126,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) @@ -186,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", ¬PercentDV) // ERROR "Printf format %d has arg ¬PercentDV of wrong type \*testdata.notPercentDStruct" + Printf("%d", notPercentDV) // ERROR "Printf format %d has arg notPercentDV of wrong type print.notPercentDStruct" + Printf("%d", ¬PercentDV) // ERROR "Printf format %d has arg ¬PercentDV of wrong type \*print.notPercentDStruct" Printf("%p", ¬PercentDV) // 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. @@ -234,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) // ERROR "Printf format %x has arg recursiveStruct1V\.next of wrong type \*testdata\.RecursiveStruct2" + 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,7 +250,7 @@ func PrintfTests() { // 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("ERROR", "%d") // ERROR "errorf format %d reads arg #1, but call has 0 args" // Printf from external package // externalprintf.Printf("%d", 42) // OK @@ -587,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" @@ -627,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 } @@ -677,5 +677,5 @@ func PointersToCompoundTypes() { type T1 struct { X *T2 } - fmt.Printf("%s\n", T1{&T2{"x"}}) // ERROR "Printf format %s has arg T1{&T2{.x.}} of wrong type testdata\.T1" + fmt.Printf("%s\n", T1{&T2{"x"}}) // ERROR "Printf format %s has arg T1{&T2{.x.}} of wrong type print\.T1" } diff --git a/src/cmd/vet/testdata/src/rangeloop/rangeloop.go b/src/cmd/vet/testdata/src/rangeloop/rangeloop.go new file mode 100644 index 00000000000000..4e21564186969d --- /dev/null +++ b/src/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/src/cmd/vet/testdata/src/shift/shift.go b/src/cmd/vet/testdata/src/shift/shift.go new file mode 100644 index 00000000000000..6b7a5ac9e180ad --- /dev/null +++ b/src/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/src/cmd/vet/testdata/src/structtag/structtag.go b/src/cmd/vet/testdata/src/structtag/structtag.go new file mode 100644 index 00000000000000..cbcc453376070a --- /dev/null +++ b/src/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/src/cmd/vet/testdata/tagtest/file1.go b/src/cmd/vet/testdata/src/tagtest/file1.go similarity index 85% rename from src/cmd/vet/testdata/tagtest/file1.go rename to src/cmd/vet/testdata/src/tagtest/file1.go index 22a1509acc0bc6..47fe3c80afe347 100644 --- a/src/cmd/vet/testdata/tagtest/file1.go +++ b/src/cmd/vet/testdata/src/tagtest/file1.go @@ -6,5 +6,8 @@ package main +import "fmt" + func main() { + fmt.Printf("%s", 0) } diff --git a/src/cmd/vet/testdata/tagtest/file2.go b/src/cmd/vet/testdata/src/tagtest/file2.go similarity index 80% rename from src/cmd/vet/testdata/tagtest/file2.go rename to src/cmd/vet/testdata/src/tagtest/file2.go index ba7dd91bbd89c8..1f45efcbf2f43e 100644 --- a/src/cmd/vet/testdata/tagtest/file2.go +++ b/src/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/src/cmd/vet/testdata/testingpkg/tests.go b/src/cmd/vet/testdata/src/testingpkg/tests.go similarity index 100% rename from src/cmd/vet/testdata/testingpkg/tests.go rename to src/cmd/vet/testdata/src/testingpkg/tests.go diff --git a/src/cmd/vet/testdata/src/testingpkg/tests_test.go b/src/cmd/vet/testdata/src/testingpkg/tests_test.go new file mode 100644 index 00000000000000..09bb98d980ecd3 --- /dev/null +++ b/src/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/src/cmd/vet/testdata/src/unmarshal/unmarshal.go b/src/cmd/vet/testdata/src/unmarshal/unmarshal.go new file mode 100644 index 00000000000000..b387bbbd234203 --- /dev/null +++ b/src/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/src/cmd/vet/testdata/src/unsafeptr/unsafeptr.go b/src/cmd/vet/testdata/src/unsafeptr/unsafeptr.go new file mode 100644 index 00000000000000..e9b866ea21b305 --- /dev/null +++ b/src/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/src/cmd/vet/testdata/src/unused/unused.go b/src/cmd/vet/testdata/src/unused/unused.go new file mode 100644 index 00000000000000..1e83e90d68fc38 --- /dev/null +++ b/src/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/src/cmd/vet/testdata/structtag.go b/src/cmd/vet/testdata/structtag.go deleted file mode 100644 index 755d52be849af9..00000000000000 --- a/src/cmd/vet/testdata/structtag.go +++ /dev/null @@ -1,113 +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 "`hello` 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 AnonymousJSONField struct { - DuplicateAnonJSON int `json:"a"` - - A int "hello" // ERROR "`hello` not compatible with reflect.StructTag.Get: bad syntax for struct tag pair" -} - -type DuplicateJSONFields struct { - JSON int `json:"a"` - DuplicateJSON int `json:"a"` // ERROR "struct field DuplicateJSON repeats json tag .a. also at structtag.go:52" - 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:52" - NonJSON int `foo:"a"` - DuplicateNonJSON int `foo:"a"` - Embedded struct { - DuplicateJSON int `json:"a"` // OK because it's not in the same struct type - } - AnonymousJSON `json:"a"` // ERROR "struct field AnonymousJSON repeats json tag .a. also at structtag.go:52" - - AnonymousJSONField // ERROR "struct field DuplicateAnonJSON repeats json tag .a. also at structtag.go:52" - - XML int `xml:"a"` - DuplicateXML int `xml:"a"` // ERROR "struct field DuplicateXML repeats xml tag .a. also at structtag.go:68" - 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:68" - NonXML int `foo:"a"` - DuplicateNonXML int `foo:"a"` - Embedded2 struct { - DuplicateXML int `xml:"a"` // OK because it's not in the same struct type - } - AnonymousXML `xml:"a"` // ERROR "struct field AnonymousXML repeats xml tag .a. also at structtag.go:68" - 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 0 is valid. - DupAttr int `xml:"b,attr"` // ERROR "struct field DupAttr repeats xml attribute tag .b. also at structtag.go:84" - DupOmitAttr int `xml:"b,omitempty,attr"` // ERROR "struct field DupOmitAttr repeats xml attribute tag .b. also at structtag.go:84" - - AnonymousXML `xml:"b,attr"` // ERROR "struct field AnonymousXML repeats xml attribute tag .b. also at structtag.go:84" - } - - AnonymousJSONField `json:"not_anon"` // ok; fields aren't embedded in JSON - AnonymousJSONField `json:"-"` // ok; entire field is ignored in JSON -} - -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/src/cmd/vet/testdata/testingpkg/tests_test.go b/src/cmd/vet/testdata/testingpkg/tests_test.go deleted file mode 100644 index f5bbc3922a99f1..00000000000000 --- a/src/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/src/cmd/vet/testdata/unmarshal.go b/src/cmd/vet/testdata/unmarshal.go deleted file mode 100644 index f541b4a414941d..00000000000000 --- a/src/cmd/vet/testdata/unmarshal.go +++ /dev/null @@ -1,60 +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. - -// This file contains tests for the unmarshal checker. - -package testdata - -import ( - "bytes" - "encoding/gob" - "encoding/json" - "encoding/xml" - "errors" - "fmt" -) - -func _() { - type t struct { - a int - } - var v t - var r io.Reader - - json.Unmarshal([]byte{}, v) // ERROR "call of Unmarshal passes non-pointer as second argument" - json.Unmarshal([]byte{}, &v) - json.NewDecoder(r).Decode(v) // ERROR "call of Decode passes non-pointer" - json.NewDecoder(r).Decode(&v) - gob.NewDecoder(r).Decode(v) // ERROR "call of Decode passes non-pointer" - gob.NewDecoder(r).Decode(&v) - xml.Unmarshal([]byte{}, v) // ERROR "call of Unmarshal passes non-pointer as second argument" - xml.Unmarshal([]byte{}, &v) - xml.NewDecoder(r).Decode(v) // ERROR "call of Decode passes non-pointer" - xml.NewDecoder(r).Decode(&v) - - var p *t - json.Unmarshal([]byte{}, p) - json.Unmarshal([]byte{}, *p) // ERROR "call of Unmarshal passes non-pointer as second argument" - json.NewDecoder(r).Decode(p) - json.NewDecoder(r).Decode(*p) // ERROR "call of Decode passes non-pointer" - gob.NewDecoder(r).Decode(p) - gob.NewDecoder(r).Decode(*p) // ERROR "call of Decode passes non-pointer" - xml.Unmarshal([]byte{}, p) - xml.Unmarshal([]byte{}, *p) // ERROR "call of Unmarshal passes non-pointer as second argument" - xml.NewDecoder(r).Decode(p) - xml.NewDecoder(r).Decode(*p) // ERROR "call of Decode passes non-pointer" - - var i interface{} - json.Unmarshal([]byte{}, i) - json.NewDecoder(r).Decode(i) - - json.Unmarshal([]byte{}, nil) // ERROR "call of Unmarshal passes non-pointer as second argument" - json.Unmarshal([]byte{}, []t{}) // ERROR "call of Unmarshal passes non-pointer as second argument" - json.Unmarshal([]byte{}, map[string]int{}) // ERROR "call of Unmarshal passes non-pointer as second argument" - json.NewDecoder(r).Decode(nil) // ERROR "call of Decode passes non-pointer" - json.NewDecoder(r).Decode([]t{}) // ERROR "call of Decode passes non-pointer" - json.NewDecoder(r).Decode(map[string]int{}) // ERROR "call of Decode passes non-pointer" - - json.Unmarshal(func() ([]byte, interface{}) { return []byte{}, v }()) -} diff --git a/src/cmd/vet/testdata/unsafeptr.go b/src/cmd/vet/testdata/unsafeptr.go deleted file mode 100644 index ce852009ea7336..00000000000000 --- a/src/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/src/cmd/vet/testdata/unused.go b/src/cmd/vet/testdata/unused.go deleted file mode 100644 index d50f6594d9b464..00000000000000 --- a/src/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/src/cmd/vet/tests.go b/src/cmd/vet/tests.go deleted file mode 100644 index 5b157084fa2570..00000000000000 --- a/src/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/src/cmd/vet/types.go b/src/cmd/vet/types.go deleted file mode 100644 index 8cb0e8e77dbeb1..00000000000000 --- a/src/cmd/vet/types.go +++ /dev/null @@ -1,345 +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.implicits = make(map[ast.Node]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, - Implicits: pkg.implicits, - } - 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 { - // Ignore identifiers that don't denote objects - // (package names, symbolic variables such as t - // in t := x.(type) of type switch headers). - if obj != nil { - pkg.growSpan(obj, id.Pos(), id.End()) - } - } - for id, obj := range pkg.uses { - pkg.growSpan(obj, id.Pos(), id.End()) - } - for node, obj := range pkg.implicits { - // A type switch with a short variable declaration - // such as t := x.(type) doesn't declare the symbolic - // variable (t in the example) at the switch header; - // instead a new variable t (with specific type) is - // declared implicitly for each case. Such variables - // are found in the types.Info.Implicits (not Defs) - // map. Add them here, assuming they are declared at - // the type cases' colon ":". - if cc, ok := node.(*ast.CaseClause); ok { - pkg.growSpan(obj, cc.Colon, cc.Colon) - } - } - 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 - } - under := typ.Elem().Underlying() - switch under.(type) { - case *types.Struct: // see below - case *types.Array: // see below - case *types.Slice: // see below - case *types.Map: // see below - default: - // Check whether the rest can print pointers. - return t&argPointer != 0 - } - // If it's a top-level pointer to a struct, array, slice, or - // map, that's equivalent in our analysis to whether we can - // print the type being pointed to. Pointers in nested levels - // are not supported to minimize fmt running into loops. - if len(inProgress) > 1 { - return false - } - return f.matchArgTypeInternal(t, under, arg, inProgress) - - 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("gc", build.Default.GOARCH) diff --git a/src/cmd/vet/unmarshal.go b/src/cmd/vet/unmarshal.go deleted file mode 100644 index 3e4c25b6b99709..00000000000000 --- a/src/cmd/vet/unmarshal.go +++ /dev/null @@ -1,72 +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. - -// This file defines the check for passing non-pointer or non-interface -// types to unmarshal and decode functions. - -package main - -import ( - "go/ast" - "go/types" - "strings" -) - -func init() { - register("unmarshal", - "check for passing non-pointer or non-interface types to unmarshal and decode functions", - checkUnmarshalArg, - callExpr) -} - -var pointerArgFuncs = map[string]int{ - "encoding/json.Unmarshal": 1, - "(*encoding/json.Decoder).Decode": 0, - "(*encoding/gob.Decoder).Decode": 0, - "encoding/xml.Unmarshal": 1, - "(*encoding/xml.Decoder).Decode": 0, -} - -func checkUnmarshalArg(f *File, n ast.Node) { - call, ok := n.(*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 - } - - info := &types.Info{Uses: f.pkg.uses, Selections: f.pkg.selectors} - name := callName(info, call) - - arg, ok := pointerArgFuncs[name] - if !ok { - return // not a function we are interested in - } - - if len(call.Args) < arg+1 { - return // not enough arguments, e.g. called with return values of another function - } - - typ := f.pkg.types[call.Args[arg]] - - if typ.Type == nil { - return // type error prevents further analysis - } - - switch typ.Type.Underlying().(type) { - case *types.Pointer, *types.Interface: - return - } - - shortname := name[strings.LastIndexByte(name, '.')+1:] - switch arg { - case 0: - f.Badf(call.Lparen, "call of %s passes non-pointer", shortname) - case 1: - f.Badf(call.Lparen, "call of %s passes non-pointer as second argument", shortname) - } -} diff --git a/src/cmd/vet/unsafeptr.go b/src/cmd/vet/unsafeptr.go deleted file mode 100644 index cb2cc818897aa4..00000000000000 --- a/src/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/src/cmd/vet/unused.go b/src/cmd/vet/unused.go deleted file mode 100644 index 02fcd841cd06db..00000000000000 --- a/src/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/src/cmd/vet/vet_test.go b/src/cmd/vet/vet_test.go index 6b2125924d7a8a..d106c5c29ce7c1 100644 --- a/src/cmd/vet/vet_test.go +++ b/src/cmd/vet/vet_test.go @@ -15,7 +15,6 @@ import ( "os/exec" "path/filepath" "regexp" - "runtime" "strconv" "strings" "sync" @@ -60,111 +59,89 @@ 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")) +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) } - wide := runtime.GOMAXPROCS(0) - if wide > len(gos) { - wide = len(gos) - } - batch := make([][]string, wide) - for i, file := range gos { - // The print.go test is run by 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) { - 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) + cmd.Env = append(os.Environ(), "GOPATH="+testdata) + return cmd } -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")) - if err != nil { - t.Fatal(err) - } - - t.Parallel() - Vet(t, append(gos, asms...)) -} - -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" { + 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) + } + asms, err := filepath.Glob(filepath.Join(dir, "*.s")) if err != nil { t.Fatal(err) } - Vet(t, gos) + 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 { @@ -185,44 +162,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", "file2.go"))) { - t.Error("file2 was included, should be excluded") + if bytes.Contains(output, []byte(filepath.Join("tagtest", dontwant))) { + t.Errorf("%s: %s was included, should be excluded", tag, dontwant) + } + 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. diff --git a/src/crypto/hmac/hmac.go b/src/crypto/hmac/hmac.go index c8c0617c47f788..801ece67ae415e 100644 --- a/src/crypto/hmac/hmac.go +++ b/src/crypto/hmac/hmac.go @@ -11,8 +11,8 @@ The receiver verifies the hash by recomputing it using the same key. Receivers should be careful to use Equal to compare MACs in order to avoid timing side-channels: - // CheckMAC reports whether messageMAC is a valid HMAC tag for message. - func CheckMAC(message, messageMAC, key []byte) bool { + // ValidMAC reports whether messageMAC is a valid HMAC tag for message. + func ValidMAC(message, messageMAC, key []byte) bool { mac := hmac.New(sha256.New, key) mac.Write(message) expectedMAC := mac.Sum(nil) diff --git a/src/database/sql/example_cli_test.go b/src/database/sql/example_cli_test.go new file mode 100644 index 00000000000000..8c61d755bb8458 --- /dev/null +++ b/src/database/sql/example_cli_test.go @@ -0,0 +1,86 @@ +// 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 sql_test + +import ( + "context" + "database/sql" + "flag" + "log" + "os" + "os/signal" + "time" +) + +var pool *sql.DB // Database connection pool. + +func Example_openDBCLI() { + id := flag.Int64("id", 0, "person ID to find") + dsn := flag.String("dsn", os.Getenv("DSN"), "connection data source name") + flag.Parse() + + if len(*dsn) == 0 { + log.Fatal("missing dsn flag") + } + if *id == 0 { + log.Fatal("missing person ID") + } + var err error + + // Opening a driver typically will not attempt to connect to the database. + pool, err = sql.Open("driver-name", *dsn) + if err != nil { + // This will not be a connection error, but a DSN parse error or + // another initialization error. + log.Fatal("unable to use data source name", err) + } + defer pool.Close() + + pool.SetConnMaxLifetime(0) + pool.SetMaxIdleConns(3) + pool.SetMaxOpenConns(3) + + ctx, stop := context.WithCancel(context.Background()) + defer stop() + + appSignal := make(chan os.Signal, 3) + signal.Notify(appSignal, os.Interrupt) + + go func() { + select { + case <-appSignal: + stop() + } + }() + + Ping(ctx) + + Query(ctx, *id) +} + +// Ping the database to verify DSN provided by the user is valid and the +// server accessible. If the ping fails exit the program with an error. +func Ping(ctx context.Context) { + ctx, cancel := context.WithTimeout(ctx, 1*time.Second) + defer cancel() + + if err := pool.PingContext(ctx); err != nil { + log.Fatalf("unable to connect to database: %v", err) + } +} + +// Query the database for the information requested and prints the results. +// If the query fails exit the program with an error. +func Query(ctx context.Context, id int64) { + ctx, cancel := context.WithTimeout(ctx, 5*time.Second) + defer cancel() + + var name string + err := pool.QueryRowContext(ctx, "select p.name from people as p where p.id = :id;", sql.Named("id", id)).Scan(&name) + if err != nil { + log.Fatal("unable to execute search query", err) + } + log.Println("name=", name) +} diff --git a/src/database/sql/example_service_test.go b/src/database/sql/example_service_test.go new file mode 100644 index 00000000000000..768307c1471a78 --- /dev/null +++ b/src/database/sql/example_service_test.go @@ -0,0 +1,158 @@ +// 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 sql_test + +import ( + "context" + "database/sql" + "encoding/json" + "fmt" + "io" + "log" + "net/http" + "time" +) + +func Example_openDBService() { + // Opening a driver typically will not attempt to connect to the database. + db, err := sql.Open("driver-name", "database=test1") + if err != nil { + // This will not be a connection error, but a DSN parse error or + // another initialization error. + log.Fatal(err) + } + db.SetConnMaxLifetime(0) + db.SetMaxIdleConns(50) + db.SetMaxOpenConns(50) + + s := &Service{db: db} + + http.ListenAndServe(":8080", s) +} + +type Service struct { + db *sql.DB +} + +func (s *Service) ServeHTTP(w http.ResponseWriter, r *http.Request) { + db := s.db + switch r.URL.Path { + default: + http.Error(w, "not found", http.StatusNotFound) + return + case "/healthz": + ctx, cancel := context.WithTimeout(r.Context(), 1*time.Second) + defer cancel() + + err := s.db.PingContext(ctx) + if err != nil { + http.Error(w, fmt.Sprintf("db down: %v", err), http.StatusFailedDependency) + return + } + w.WriteHeader(http.StatusOK) + return + case "/quick-action": + // This is a short SELECT. Use the request context as the base of + // the context timeout. + ctx, cancel := context.WithTimeout(r.Context(), 3*time.Second) + defer cancel() + + id := 5 + org := 10 + var name string + err := db.QueryRowContext(ctx, ` +select + p.name +from + people as p + join organization as o on p.organization = o.id +where + p.id = :id + and o.id = :org +;`, + sql.Named("id", id), + sql.Named("org", org), + ).Scan(&name) + if err != nil { + if err == sql.ErrNoRows { + http.Error(w, "not found", http.StatusNotFound) + return + } + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + io.WriteString(w, name) + return + case "/long-action": + // This is a long SELECT. Use the request context as the base of + // the context timeout, but give it some time to finish. If + // the client cancels before the query is done the query will also + // be canceled. + ctx, cancel := context.WithTimeout(r.Context(), 60*time.Second) + defer cancel() + + var names []string + rows, err := db.QueryContext(ctx, "select p.name from people as p where p.active = true;") + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + for rows.Next() { + var name string + err = rows.Scan(&name) + if err != nil { + break + } + names = append(names, name) + } + // Check for errors during rows "Close". + // This may be more important if multiple statements are executed + // in a single batch and rows were written as well as read. + if closeErr := rows.Close(); closeErr != nil { + http.Error(w, closeErr.Error(), http.StatusInternalServerError) + return + } + + // Check for row scan error. + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Check for errors during row iteration. + if err = rows.Err(); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + json.NewEncoder(w).Encode(names) + return + case "/async-action": + // This action has side effects that we want to preserve + // even if the client cancels the HTTP request part way through. + // For this we do not use the http request context as a base for + // the timeout. + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + var orderRef = "ABC123" + tx, err := db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelSerializable}) + _, err = tx.ExecContext(ctx, "stored_proc_name", orderRef) + + if err != nil { + tx.Rollback() + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + err = tx.Commit() + if err != nil { + http.Error(w, "action in unknown state, check state before attempting again", http.StatusInternalServerError) + return + } + w.WriteHeader(http.StatusOK) + return + } +} diff --git a/src/database/sql/example_test.go b/src/database/sql/example_test.go index da938b071a121d..6f9bd91276edfc 100644 --- a/src/database/sql/example_test.go +++ b/src/database/sql/example_test.go @@ -13,8 +13,10 @@ import ( "time" ) -var ctx = context.Background() -var db *sql.DB +var ( + ctx context.Context + db *sql.DB +) func ExampleDB_QueryContext() { age := 27 @@ -24,13 +26,25 @@ func ExampleDB_QueryContext() { } defer rows.Close() names := make([]string, 0) + for rows.Next() { var name string if err := rows.Scan(&name); err != nil { + // Check for a scan error. + // Query rows will be closed with defer. log.Fatal(err) } names = append(names, name) } + // If the database is being written to ensure to check for Close + // errors that may be returned from the driver. The query may + // encounter an auto-commit error and be forced to rollback changes. + rerr := rows.Close() + if rerr != nil { + log.Fatal(err) + } + + // Rows.Err will report the last error encountered by Rows.Scan. if err := rows.Err(); err != nil { log.Fatal(err) } @@ -44,11 +58,11 @@ func ExampleDB_QueryRowContext() { err := db.QueryRowContext(ctx, "SELECT username, created_at FROM users WHERE id=?", id).Scan(&username, &created) switch { case err == sql.ErrNoRows: - log.Printf("No user with id %d", id) + log.Printf("no user with id %d\n", id) case err != nil: - log.Fatal(err) + log.Fatalf("query error: %v\n", err) default: - fmt.Printf("Username is %s, account created on %s\n", username, created) + log.Printf("username is %q, account created on %s\n", username, created) } } @@ -63,7 +77,7 @@ func ExampleDB_ExecContext() { log.Fatal(err) } if rows != 1 { - panic(err) + log.Fatalf("expected to affect 1 row, affected %d", rows) } } @@ -104,10 +118,10 @@ from if err := rows.Scan(&id, &name); err != nil { log.Fatal(err) } - fmt.Printf("id %d name is %s\n", id, name) + log.Printf("id %d name is %s\n", id, name) } if !rows.NextResultSet() { - log.Fatal("expected more result sets", rows.Err()) + log.Fatalf("expected more result sets: %v", rows.Err()) } var roleMap = map[int64]string{ 1: "user", @@ -122,7 +136,7 @@ from if err := rows.Scan(&id, &role); err != nil { log.Fatal(err) } - fmt.Printf("id %d has role %s\n", id, roleMap[role]) + log.Printf("id %d has role %s\n", id, roleMap[role]) } if err := rows.Err(); err != nil { log.Fatal(err) @@ -130,11 +144,23 @@ from } func ExampleDB_PingContext() { + // Ping and PingContext may be used to determine if communication with + // the database server is still possible. + // + // When used in a command line application Ping may be used to establish + // that further queries are possible; that the provided DSN is valid. + // + // When used in long running service Ping may be part of the health + // checking system. + ctx, cancel := context.WithTimeout(ctx, 1*time.Second) defer cancel() + + status := "up" if err := db.PingContext(ctx); err != nil { - log.Fatal(err) + status = "down" } + log.Println(status) } func ExampleConn_BeginTx() { @@ -162,7 +188,7 @@ func ExampleConn_ExecContext() { } defer conn.Close() // Return the connection to the pool. id := 41 - result, err := conn.ExecContext(ctx, `UPDATE balances SET balance = balance + 10 WHERE user_id = ?`, id) + result, err := conn.ExecContext(ctx, `UPDATE balances SET balance = balance + 10 WHERE user_id = ?;`, id) if err != nil { log.Fatal(err) } @@ -171,7 +197,7 @@ func ExampleConn_ExecContext() { log.Fatal(err) } if rows != 1 { - panic(err) + log.Fatalf("expected single row affected, got %d rows affected", rows) } } @@ -184,9 +210,9 @@ func ExampleTx_ExecContext() { _, execErr := tx.ExecContext(ctx, "UPDATE users SET status = ? WHERE id = ?", "paid", id) if execErr != nil { if rollbackErr := tx.Rollback(); rollbackErr != nil { - log.Printf("Could not roll back: %v\n", rollbackErr) + log.Fatalf("update failed: %v, unable to rollback: %v\n", execErr, rollbackErr) } - log.Fatal(execErr) + log.Fatalf("update failed: %v", execErr) } if err := tx.Commit(); err != nil { log.Fatal(err) @@ -199,17 +225,17 @@ func ExampleTx_Rollback() { log.Fatal(err) } id := 53 - _, err = tx.ExecContext(ctx, "UPDATE drivers SET status = ? WHERE id = ?", "assigned", id) + _, err = tx.ExecContext(ctx, "UPDATE drivers SET status = ? WHERE id = ?;", "assigned", id) if err != nil { if rollbackErr := tx.Rollback(); rollbackErr != nil { - log.Printf("Could not roll back: %v\n", rollbackErr) + log.Fatalf("update drivers: unable to rollback: %v", rollbackErr) } log.Fatal(err) } - _, err = tx.ExecContext(ctx, "UPDATE pickups SET driver_id = $1", id) + _, err = tx.ExecContext(ctx, "UPDATE pickups SET driver_id = $1;", id) if err != nil { if rollbackErr := tx.Rollback(); rollbackErr != nil { - log.Printf("Could not roll back: %v\n", rollbackErr) + log.Fatalf("update failed: %v, unable to back: %v", err, rollbackErr) } log.Fatal(err) } @@ -225,17 +251,18 @@ func ExampleStmt() { log.Fatal(err) } defer stmt.Close() + // Then reuse it each time you need to issue the query. id := 43 var username string err = stmt.QueryRowContext(ctx, id).Scan(&username) switch { case err == sql.ErrNoRows: - log.Printf("No user with that ID.") + log.Fatalf("no user with id %d", id) case err != nil: log.Fatal(err) default: - fmt.Printf("Username is %s\n", username) + log.Printf("username is %s\n", username) } } @@ -245,17 +272,19 @@ func ExampleStmt_QueryRowContext() { if err != nil { log.Fatal(err) } + defer stmt.Close() + // Then reuse it each time you need to issue the query. id := 43 var username string err = stmt.QueryRowContext(ctx, id).Scan(&username) switch { case err == sql.ErrNoRows: - log.Printf("No user with that ID.") + log.Fatalf("no user with id %d", id) case err != nil: log.Fatal(err) default: - fmt.Printf("Username is %s\n", username) + log.Printf("username is %s\n", username) } } @@ -266,6 +295,7 @@ func ExampleRows() { log.Fatal(err) } defer rows.Close() + names := make([]string, 0) for rows.Next() { var name string @@ -274,8 +304,9 @@ func ExampleRows() { } names = append(names, name) } + // Check for errors from iterating over rows. if err := rows.Err(); err != nil { log.Fatal(err) } - fmt.Printf("%s are %d years old", strings.Join(names, ", "), age) + log.Printf("%s are %d years old", strings.Join(names, ", "), age) } diff --git a/src/encoding/asn1/asn1.go b/src/encoding/asn1/asn1.go index 3cfd9d1276497f..dbb95e94a151ee 100644 --- a/src/encoding/asn1/asn1.go +++ b/src/encoding/asn1/asn1.go @@ -329,17 +329,26 @@ func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err error) // UTCTime -func parseUTCTime(bytes []byte) (ret time.Time, err error) { +func parseUTCTime(bytes []byte, format string) (ret time.Time, err error) { s := string(bytes) + var formatStr string - formatStr := "0601021504Z0700" - ret, err = time.Parse(formatStr, s) - if err != nil { - formatStr = "060102150405Z0700" + if format != "" { + formatStr = format ret, err = time.Parse(formatStr, s) - } - if err != nil { - return + if err != nil { + return + } + } else { + formatStr = "0601021504Z0700" + ret, err = time.Parse(formatStr, s) + if err != nil { + formatStr = "060102150405Z0700" + ret, err = time.Parse(formatStr, s) + } + if err != nil { + return + } } if serialized := ret.Format(formatStr); serialized != s { @@ -357,8 +366,11 @@ func parseUTCTime(bytes []byte) (ret time.Time, err error) { // parseGeneralizedTime parses the GeneralizedTime from the given byte slice // and returns the resulting time. -func parseGeneralizedTime(bytes []byte) (ret time.Time, err error) { - const formatStr = "20060102150405Z0700" +func parseGeneralizedTime(bytes []byte, format string) (ret time.Time, err error) { + formatStr := "20060102150405Z0700" + if format != "" { + formatStr = format + } s := string(bytes) if ret, err = time.Parse(formatStr, s); err != nil { @@ -686,9 +698,9 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam case TagOID: result, err = parseObjectIdentifier(innerBytes) case TagUTCTime: - result, err = parseUTCTime(innerBytes) + result, err = parseUTCTime(innerBytes, params.timeFormat) case TagGeneralizedTime: - result, err = parseGeneralizedTime(innerBytes) + result, err = parseGeneralizedTime(innerBytes, params.timeFormat) case TagOctetString: result = innerBytes default: @@ -769,7 +781,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam // Special case for time: UTCTime and GeneralizedTime both map to the // Go type time.Time. - if universalTag == TagUTCTime && t.tag == TagGeneralizedTime && t.class == ClassUniversal { + if params.timeType == TagGeneralizedTime || (universalTag == TagUTCTime && t.tag == TagGeneralizedTime && t.class == ClassUniversal) { universalTag = TagGeneralizedTime } @@ -843,9 +855,9 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam var time time.Time var err1 error if universalTag == TagUTCTime { - time, err1 = parseUTCTime(innerBytes) + time, err1 = parseUTCTime(innerBytes, params.timeFormat) } else { - time, err1 = parseGeneralizedTime(innerBytes) + time, err1 = parseGeneralizedTime(innerBytes, params.timeFormat) } if err1 == nil { v.Set(reflect.ValueOf(time)) diff --git a/src/encoding/asn1/asn1_test.go b/src/encoding/asn1/asn1_test.go index f0a54e0cb2e699..33de1ed488ecad 100644 --- a/src/encoding/asn1/asn1_test.go +++ b/src/encoding/asn1/asn1_test.go @@ -258,51 +258,54 @@ func TestObjectIdentifier(t *testing.T) { } type timeTest struct { - in string - ok bool - out time.Time + in string + ok bool + out time.Time + format string } var utcTestData = []timeTest{ - {"910506164540-0700", true, time.Date(1991, 05, 06, 16, 45, 40, 0, time.FixedZone("", -7*60*60))}, - {"910506164540+0730", true, time.Date(1991, 05, 06, 16, 45, 40, 0, time.FixedZone("", 7*60*60+30*60))}, - {"910506234540Z", true, time.Date(1991, 05, 06, 23, 45, 40, 0, time.UTC)}, - {"9105062345Z", true, time.Date(1991, 05, 06, 23, 45, 0, 0, time.UTC)}, - {"5105062345Z", true, time.Date(1951, 05, 06, 23, 45, 0, 0, time.UTC)}, - {"a10506234540Z", false, time.Time{}}, - {"91a506234540Z", false, time.Time{}}, - {"9105a6234540Z", false, time.Time{}}, - {"910506a34540Z", false, time.Time{}}, - {"910506334a40Z", false, time.Time{}}, - {"91050633444aZ", false, time.Time{}}, - {"910506334461Z", false, time.Time{}}, - {"910506334400Za", false, time.Time{}}, + {"910506164540-0700", true, time.Date(1991, 05, 06, 16, 45, 40, 0, time.FixedZone("", -7*60*60)), ""}, + {"910506164540+0730", true, time.Date(1991, 05, 06, 16, 45, 40, 0, time.FixedZone("", 7*60*60+30*60)), ""}, + {"910506234540Z", true, time.Date(1991, 05, 06, 23, 45, 40, 0, time.UTC), ""}, + {"9105062345Z", true, time.Date(1991, 05, 06, 23, 45, 0, 0, time.UTC), ""}, + {"5105062345Z", true, time.Date(1951, 05, 06, 23, 45, 0, 0, time.UTC), ""}, + // Test the use of specified custom formats that can be supplied using the timeFormat tag + {"19510506234500.123456Z", true, time.Date(1951, 05, 06, 23, 45, 0, 123456000, time.UTC), "20060102150405.999999Z0700"}, + {"a10506234540Z", false, time.Time{}, ""}, + {"91a506234540Z", false, time.Time{}, ""}, + {"9105a6234540Z", false, time.Time{}, ""}, + {"910506a34540Z", false, time.Time{}, ""}, + {"910506334a40Z", false, time.Time{}, ""}, + {"91050633444aZ", false, time.Time{}, ""}, + {"910506334461Z", false, time.Time{}, ""}, + {"910506334400Za", false, time.Time{}, ""}, /* These are invalid times. However, the time package normalises times * and they were accepted in some versions. See #11134. */ - {"000100000000Z", false, time.Time{}}, - {"101302030405Z", false, time.Time{}}, - {"100002030405Z", false, time.Time{}}, - {"100100030405Z", false, time.Time{}}, - {"100132030405Z", false, time.Time{}}, - {"100231030405Z", false, time.Time{}}, - {"100102240405Z", false, time.Time{}}, - {"100102036005Z", false, time.Time{}}, - {"100102030460Z", false, time.Time{}}, - {"-100102030410Z", false, time.Time{}}, - {"10-0102030410Z", false, time.Time{}}, - {"10-0002030410Z", false, time.Time{}}, - {"1001-02030410Z", false, time.Time{}}, - {"100102-030410Z", false, time.Time{}}, - {"10010203-0410Z", false, time.Time{}}, - {"1001020304-10Z", false, time.Time{}}, + {"000100000000Z", false, time.Time{}, ""}, + {"101302030405Z", false, time.Time{}, ""}, + {"100002030405Z", false, time.Time{}, ""}, + {"100100030405Z", false, time.Time{}, ""}, + {"100132030405Z", false, time.Time{}, ""}, + {"100231030405Z", false, time.Time{}, ""}, + {"100102240405Z", false, time.Time{}, ""}, + {"100102036005Z", false, time.Time{}, ""}, + {"100102030460Z", false, time.Time{}, ""}, + {"-100102030410Z", false, time.Time{}, ""}, + {"10-0102030410Z", false, time.Time{}, ""}, + {"10-0002030410Z", false, time.Time{}, ""}, + {"1001-02030410Z", false, time.Time{}, ""}, + {"100102-030410Z", false, time.Time{}, ""}, + {"10010203-0410Z", false, time.Time{}, ""}, + {"1001020304-10Z", false, time.Time{}, ""}, } func TestUTCTime(t *testing.T) { for i, test := range utcTestData { - ret, err := parseUTCTime([]byte(test.in)) + ret, err := parseUTCTime([]byte(test.in), test.format) if err != nil { if test.ok { - t.Errorf("#%d: parseUTCTime(%q) = error %v", i, test.in, err) + t.Errorf("#%d: parseUTCTime(%q, %q) = error %v", i, test.in, test.format, err) } continue } @@ -320,33 +323,35 @@ func TestUTCTime(t *testing.T) { } var generalizedTimeTestData = []timeTest{ - {"20100102030405Z", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.UTC)}, - {"20100102030405", false, time.Time{}}, - {"20100102030405+0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", 6*60*60+7*60))}, - {"20100102030405-0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", -6*60*60-7*60))}, + {"20100102030405Z", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.UTC), ""}, + {"20100102030405", false, time.Time{}, ""}, + {"20100102030405+0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", 6*60*60+7*60)), ""}, + {"20100102030405-0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", -6*60*60-7*60)), ""}, + // Test the use of specified custom formats that can be supplied using the timeFormat tag + {"19510506234500.123456Z", true, time.Date(1951, 05, 06, 23, 45, 0, 123456000, time.UTC), "20060102150405.999999Z0700"}, /* These are invalid times. However, the time package normalises times * and they were accepted in some versions. See #11134. */ - {"00000100000000Z", false, time.Time{}}, - {"20101302030405Z", false, time.Time{}}, - {"20100002030405Z", false, time.Time{}}, - {"20100100030405Z", false, time.Time{}}, - {"20100132030405Z", false, time.Time{}}, - {"20100231030405Z", false, time.Time{}}, - {"20100102240405Z", false, time.Time{}}, - {"20100102036005Z", false, time.Time{}}, - {"20100102030460Z", false, time.Time{}}, - {"-20100102030410Z", false, time.Time{}}, - {"2010-0102030410Z", false, time.Time{}}, - {"2010-0002030410Z", false, time.Time{}}, - {"201001-02030410Z", false, time.Time{}}, - {"20100102-030410Z", false, time.Time{}}, - {"2010010203-0410Z", false, time.Time{}}, - {"201001020304-10Z", false, time.Time{}}, + {"00000100000000Z", false, time.Time{}, ""}, + {"20101302030405Z", false, time.Time{}, ""}, + {"20100002030405Z", false, time.Time{}, ""}, + {"20100100030405Z", false, time.Time{}, ""}, + {"20100132030405Z", false, time.Time{}, ""}, + {"20100231030405Z", false, time.Time{}, ""}, + {"20100102240405Z", false, time.Time{}, ""}, + {"20100102036005Z", false, time.Time{}, ""}, + {"20100102030460Z", false, time.Time{}, ""}, + {"-20100102030410Z", false, time.Time{}, ""}, + {"2010-0102030410Z", false, time.Time{}, ""}, + {"2010-0002030410Z", false, time.Time{}, ""}, + {"201001-02030410Z", false, time.Time{}, ""}, + {"20100102-030410Z", false, time.Time{}, ""}, + {"2010010203-0410Z", false, time.Time{}, ""}, + {"201001020304-10Z", false, time.Time{}, ""}, } func TestGeneralizedTime(t *testing.T) { for i, test := range generalizedTimeTestData { - ret, err := parseGeneralizedTime([]byte(test.in)) + ret, err := parseGeneralizedTime([]byte(test.in), test.format) if (err == nil) != test.ok { t.Errorf("#%d: Incorrect error result (did fail? %v, expected: %v)", i, err == nil, test.ok) } diff --git a/src/encoding/asn1/common.go b/src/encoding/asn1/common.go index 255d1ebfa8990e..e6664defc4f3f5 100644 --- a/src/encoding/asn1/common.go +++ b/src/encoding/asn1/common.go @@ -82,6 +82,7 @@ type fieldParameters struct { timeType int // the time tag to use when marshaling. set bool // true iff this should be encoded as a SET omitEmpty bool // true iff this should be omitted if empty when marshaling. + timeFormat string // the time format to use when unmarshalling. // Invariants: // if explicit is set, tag is non-nil. @@ -102,6 +103,8 @@ func parseFieldParameters(str string) (ret fieldParameters) { } case part == "generalized": ret.timeType = TagGeneralizedTime + case strings.HasPrefix(part, "timeFormat:"): + ret.timeFormat = part[11:] case part == "utc": ret.timeType = TagUTCTime case part == "ia5": diff --git a/src/encoding/pem/pem_test.go b/src/encoding/pem/pem_test.go index a1b5afac0866d7..204611bda02d7a 100644 --- a/src/encoding/pem/pem_test.go +++ b/src/encoding/pem/pem_test.go @@ -26,6 +26,10 @@ var getLineTests = []GetLineTest{ {"abc\r\nd", "abc", "d"}, {"\nabc", "", "abc"}, {"\r\nabc", "", "abc"}, + {"abc\t \nd", "abc", "d"}, + {"\t abc\nd", "\t abc", "d"}, + {"abc\n\t d", "abc", "\t d"}, + {"abc\nd\t ", "abc", "d\t "}, } func TestGetLine(t *testing.T) { diff --git a/src/go/doc/example.go b/src/go/doc/example.go index cf3547810ad1be..45350f8fd3532f 100644 --- a/src/go/doc/example.go +++ b/src/go/doc/example.go @@ -268,6 +268,11 @@ func playExample(file *ast.File, f *ast.FuncDecl) *ast.File { if err != nil { continue } + if p == "syscall/js" { + // We don't support examples that import syscall/js, + // because the package syscall/js is not available in the playground. + return nil + } n := path.Base(p) if s.Name != nil { n = s.Name.Name diff --git a/src/internal/cpu/cpu.go b/src/internal/cpu/cpu.go index e210a6db9ec0bd..5ac0989d79bd46 100644 --- a/src/internal/cpu/cpu.go +++ b/src/internal/cpu/cpu.go @@ -6,7 +6,8 @@ // used by the Go standard library. package cpu -// DebugOptions is set to true by the runtime if the OS supports GODEBUGCPU. +// DebugOptions is set to true by the runtime if the OS supports reading +// GODEBUG early in runtime startup. // This should not be changed after it is initialized. var DebugOptions bool @@ -130,13 +131,14 @@ type s390x struct { // Initialize examines the processor and sets the relevant variables above. // This is called by the runtime package early in program initialization, -// before normal init functions are run. env is set by runtime if the OS supports GODEBUGCPU. +// before normal init functions are run. env is set by runtime if the OS supports +// cpu feature options in GODEBUG. func Initialize(env string) { doinit() processOptions(env) } -// options contains the cpu debug options that can be used in GODEBUGCPU. +// options contains the cpu debug options that can be used in GODEBUG. // Options are arch dependent and are added by the arch specific doinit functions. // Features that are mandatory for the specific GOARCH should not be added to options // (e.g. SSE2 on amd64). @@ -146,16 +148,16 @@ var options []option type option struct { Name string Feature *bool - Specified bool // whether feature value was specified in GODEBUGCPU + Specified bool // whether feature value was specified in GODEBUG Enable bool // whether feature should be enabled Required bool // whether feature is mandatory and can not be disabled } // processOptions enables or disables CPU feature values based on the parsed env string. -// The env string is expected to be of the form feature1=value1,feature2=value2... +// The env string is expected to be of the form cpu.feature1=value1,cpu.feature2=value2... // where feature names is one of the architecture specifc list stored in the // cpu packages options variable and values are either 'on' or 'off'. -// If env contains all=off then all cpu features referenced through the options +// If env contains cpu.all=off then all cpu features referenced through the options // variable are disabled. Other feature names and values result in warning messages. func processOptions(env string) { field: @@ -167,12 +169,15 @@ field: } else { field, env = env[:i], env[i+1:] } + if len(field) < 4 || field[:4] != "cpu." { + continue + } i = indexByte(field, '=') if i < 0 { - print("GODEBUGCPU: no value specified for \"", field, "\"\n") + print("GODEBUG: no value specified for \"", field, "\"\n") continue } - key, value := field[:i], field[i+1:] + key, value := field[4:i], field[i+1:] // e.g. "SSE2", "on" var enable bool switch value { @@ -181,7 +186,7 @@ field: case "off": enable = false default: - print("GODEBUGCPU: value \"", value, "\" not supported for option ", key, "\n") + print("GODEBUG: value \"", value, "\" not supported for cpu option \"", key, "\"\n") continue field } @@ -201,7 +206,7 @@ field: } } - print("GODEBUGCPU: unknown cpu feature \"", key, "\"\n") + print("GODEBUG: unknown cpu feature \"", key, "\"\n") } for _, o := range options { @@ -210,12 +215,12 @@ field: } if o.Enable && !*o.Feature { - print("GODEBUGCPU: can not enable \"", o.Name, "\", missing hardware support\n") + print("GODEBUG: can not enable \"", o.Name, "\", missing CPU support\n") continue } if !o.Enable && o.Required { - print("GODEBUGCPU: can not disable \"", o.Name, "\", required feature\n") + print("GODEBUG: can not disable \"", o.Name, "\", required CPU feature\n") continue } diff --git a/src/internal/cpu/cpu_test.go b/src/internal/cpu/cpu_test.go index b01e212ce8b5c9..e09bd2d8b99f70 100644 --- a/src/internal/cpu/cpu_test.go +++ b/src/internal/cpu/cpu_test.go @@ -41,7 +41,7 @@ func runDebugOptionsTest(t *testing.T, test string, options string) { testenv.MustHaveExec(t) - env := "GODEBUGCPU=" + options + env := "GODEBUG=" + options cmd := exec.Command(os.Args[0], "-test.run="+test) cmd.Env = append(cmd.Env, env) @@ -58,14 +58,14 @@ func runDebugOptionsTest(t *testing.T, test string, options string) { } func TestDisableAllCapabilities(t *testing.T) { - runDebugOptionsTest(t, "TestAllCapabilitiesDisabled", "all=off") + runDebugOptionsTest(t, "TestAllCapabilitiesDisabled", "cpu.all=off") } func TestAllCapabilitiesDisabled(t *testing.T) { MustHaveDebugOptionsSupport(t) - if os.Getenv("GODEBUGCPU") != "all=off" { - t.Skipf("skipping test: GODEBUGCPU=all=off not set") + if os.Getenv("GODEBUG") != "cpu.all=off" { + t.Skipf("skipping test: GODEBUG=cpu.all=off not set") } for _, o := range Options { diff --git a/src/internal/cpu/cpu_x86_test.go b/src/internal/cpu/cpu_x86_test.go index a79be41811f462..9e93d1af5d72c6 100644 --- a/src/internal/cpu/cpu_x86_test.go +++ b/src/internal/cpu/cpu_x86_test.go @@ -20,14 +20,14 @@ func TestX86ifAVX2hasAVX(t *testing.T) { } func TestDisableSSE2(t *testing.T) { - runDebugOptionsTest(t, "TestSSE2DebugOption", "sse2=off") + runDebugOptionsTest(t, "TestSSE2DebugOption", "cpu.sse2=off") } func TestSSE2DebugOption(t *testing.T) { MustHaveDebugOptionsSupport(t) - if os.Getenv("GODEBUGCPU") != "sse2=off" { - t.Skipf("skipping test: GODEBUGCPU=sse2=off not set") + if os.Getenv("GODEBUG") != "cpu.sse2=off" { + t.Skipf("skipping test: GODEBUG=cpu.sse2=off not set") } want := runtime.GOARCH != "386" // SSE2 can only be disabled on 386. @@ -37,14 +37,14 @@ func TestSSE2DebugOption(t *testing.T) { } func TestDisableSSE3(t *testing.T) { - runDebugOptionsTest(t, "TestSSE3DebugOption", "sse3=off") + runDebugOptionsTest(t, "TestSSE3DebugOption", "cpu.sse3=off") } func TestSSE3DebugOption(t *testing.T) { MustHaveDebugOptionsSupport(t) - if os.Getenv("GODEBUGCPU") != "sse3=off" { - t.Skipf("skipping test: GODEBUGCPU=sse3=off not set") + if os.Getenv("GODEBUG") != "cpu.sse3=off" { + t.Skipf("skipping test: GODEBUG=cpu.sse3=off not set") } want := false diff --git a/src/make.bash b/src/make.bash index 78882d98341f6e..13497eb039d89e 100755 --- a/src/make.bash +++ b/src/make.bash @@ -64,6 +64,7 @@ set -e unset GOBIN # Issue 14340 unset GOFLAGS +unset GO111MODULE if [ ! -f run.bash ]; then echo 'make.bash must be run from $GOROOT/src' 1>&2 diff --git a/src/make.bat b/src/make.bat index 9ca7afb5aa9790..69275e22568a2e 100644 --- a/src/make.bat +++ b/src/make.bat @@ -48,6 +48,7 @@ setlocal set GOBUILDFAIL=0 set GOFLAGS= +set GO111MODULE= if exist make.bat goto ok echo Must run make.bat from Go src directory. diff --git a/src/make.rc b/src/make.rc index a97dfc8a0105fc..5f888c19fd7bdb 100755 --- a/src/make.rc +++ b/src/make.rc @@ -48,6 +48,7 @@ if(~ $1 -v) { } GOFLAGS=() +GO111MODULE=() GOROOT = `{cd .. && pwd} if(! ~ $#GOROOT_BOOTSTRAP 1) GOROOT_BOOTSTRAP = $home/go1.4 diff --git a/src/mime/mediatype.go b/src/mime/mediatype.go index 3d480a9d7e7c40..05390773a8afa9 100644 --- a/src/mime/mediatype.go +++ b/src/mime/mediatype.go @@ -56,7 +56,8 @@ func FormatMediaType(t string, param map[string]string) string { b.WriteByte('"') offset := 0 - for index, character := range value { + for index := 0; index < len(value); index++ { + character := value[index] if character == '"' || character == '\\' { b.WriteString(value[offset:index]) offset = index diff --git a/src/mime/mediatype_test.go b/src/mime/mediatype_test.go index 35b311a4a58b1d..945a8189e171c9 100644 --- a/src/mime/mediatype_test.go +++ b/src/mime/mediatype_test.go @@ -481,6 +481,8 @@ var formatTests = []formatTest{ {"noslash", map[string]string{"X": "Y"}, "noslash; x=Y"}, // e.g. Content-Disposition values (RFC 2183); issue 11289 {"foo bar/baz", nil, ""}, {"foo/bar baz", nil, ""}, + {"attachment", map[string]string{"filename": "ĄĄŽŽČČŠŠ"}, ""}, + {"attachment", map[string]string{"filename": "ÁÁÊÊÇÇÎÎ"}, ""}, {"foo/BAR", nil, "foo/bar"}, {"foo/BAR", map[string]string{"X": "Y"}, "foo/bar; x=Y"}, {"foo/BAR", map[string]string{"space": "With space"}, `foo/bar; space="With space"`}, diff --git a/src/net/http/cookie.go b/src/net/http/cookie.go index 289c3c37b1989b..ad7903f074c185 100644 --- a/src/net/http/cookie.go +++ b/src/net/http/cookie.go @@ -38,7 +38,7 @@ type Cookie struct { // SameSite allows a server to define a cookie attribute making it impossible for // the browser to send this cookie along with cross-site requests. The main -// goal is to mitigate the risk of cross-origin information leakage, and provides +// goal is to mitigate the risk of cross-origin information leakage, and provide // some protection against cross-site request forgery attacks. // // See https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00 for details. diff --git a/src/os/removeall_at.go b/src/os/removeall_at.go index eb220bd103f0c1..777690ec661056 100644 --- a/src/os/removeall_at.go +++ b/src/os/removeall_at.go @@ -13,9 +13,16 @@ import ( ) func RemoveAll(path string) error { - // Not allowed in unix - if path == "" || endsWithDot(path) { - return syscall.EINVAL + if path == "" { + // fail silently to retain compatibility with previous behavior + // of RemoveAll. See issue 28830. + return nil + } + + // The rmdir system call does not permit removing ".", + // so we don't permit it either. + if endsWithDot(path) { + return &PathError{"RemoveAll", path, syscall.EINVAL} } // RemoveAll recurses by deleting the path base from @@ -124,16 +131,13 @@ func openFdAt(fd int, path string) (*File, error) { return NewFile(uintptr(fd), path), nil } +// endsWithDot returns whether the final component of path is ".". func endsWithDot(path string) bool { - if path == "." || path == ".." { + if path == "." { return true } - if len(path) >= 2 && path[len(path)-2:] == "/." { + if len(path) >= 2 && path[len(path)-1] == '.' && IsPathSeparator(path[len(path)-2]) { return true } - if len(path) >= 3 && path[len(path)-3:] == "/.." { - return true - } - return false } diff --git a/src/os/removeall_noat.go b/src/os/removeall_noat.go index d1dd43ff6ac44d..d382b42af33f93 100644 --- a/src/os/removeall_noat.go +++ b/src/os/removeall_noat.go @@ -16,6 +16,12 @@ import ( // it encounters. If the path does not exist, RemoveAll // returns nil (no error). func RemoveAll(path string) error { + if path == "" { + // fail silently to retain compatibility with previous behavior + // of RemoveAll. See issue 28830. + return nil + } + // Simple case: if Remove works, we're done. err := Remove(path) if err == nil || IsNotExist(err) { diff --git a/src/os/removeall_test.go b/src/os/removeall_test.go index 5eec8cd1547310..1c9f16322547ae 100644 --- a/src/os/removeall_test.go +++ b/src/os/removeall_test.go @@ -21,6 +21,10 @@ func TestRemoveAll(t *testing.T) { } defer RemoveAll(tmpDir) + if err := RemoveAll(""); err != nil { + t.Errorf("RemoveAll(\"\"): %v; want nil", err) + } + file := filepath.Join(tmpDir, "file") path := filepath.Join(tmpDir, "_TestRemoveAll_") fpath := filepath.Join(path, "file") @@ -211,13 +215,6 @@ func TestRemoveAllLongPath(t *testing.T) { } func TestRemoveAllDot(t *testing.T) { - switch runtime.GOOS { - case "aix", "darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris": - break - default: - t.Skip("skipping for not implemented platforms") - } - prevDir, err := Getwd() if err != nil { t.Fatalf("Could not get wd: %s", err) @@ -238,13 +235,32 @@ func TestRemoveAllDot(t *testing.T) { t.Errorf("RemoveAll succeed to remove .") } - err = RemoveAll("..") - if err == nil { - t.Errorf("RemoveAll succeed to remove ..") - } - err = Chdir(prevDir) if err != nil { t.Fatalf("Could not chdir %s: %s", prevDir, err) } } + +func TestRemoveAllDotDot(t *testing.T) { + t.Parallel() + + tempDir, err := ioutil.TempDir("", "TestRemoveAllDotDot-") + if err != nil { + t.Fatal(err) + } + defer RemoveAll(tempDir) + + subdir := filepath.Join(tempDir, "x") + subsubdir := filepath.Join(subdir, "y") + if err := MkdirAll(subsubdir, 0777); err != nil { + t.Fatal(err) + } + if err := RemoveAll(filepath.Join(subsubdir, "..")); err != nil { + t.Error(err) + } + for _, dir := range []string{subsubdir, subdir} { + if _, err := Stat(dir); err == nil { + t.Errorf("%s: exists after RemoveAll", dir) + } + } +} diff --git a/src/reflect/type.go b/src/reflect/type.go index 5bbab79fc0775d..f48f9cf09de464 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -593,6 +593,7 @@ const ( kindMask = (1 << 5) - 1 ) +// String returns the name of k. func (k Kind) String() string { if int(k) < len(kindNames) { return kindNames[k] diff --git a/src/regexp/example_test.go b/src/regexp/example_test.go index d65464665f7798..3008c56b6bea94 100644 --- a/src/regexp/example_test.go +++ b/src/regexp/example_test.go @@ -25,12 +25,26 @@ func Example() { // false } +func ExampleMatch() { + matched, err := regexp.Match(`foo.*`, []byte(`seafood`)) + fmt.Println(matched, err) + matched, err = regexp.Match(`bar.*`, []byte(`seafood`)) + fmt.Println(matched, err) + matched, err = regexp.Match(`a(b`, []byte(`seafood`)) + fmt.Println(matched, err) + + // Output: + // true + // false + // false error parsing regexp: missing closing ): `a(b` +} + func ExampleMatchString() { - matched, err := regexp.MatchString("foo.*", "seafood") + matched, err := regexp.MatchString(`foo.*`, "seafood") fmt.Println(matched, err) - matched, err = regexp.MatchString("bar.*", "seafood") + matched, err = regexp.MatchString(`bar.*`, "seafood") fmt.Println(matched, err) - matched, err = regexp.MatchString("a(b", "seafood") + matched, err = regexp.MatchString(`a(b`, "seafood") fmt.Println(matched, err) // Output: // true @@ -39,13 +53,53 @@ func ExampleMatchString() { } func ExampleQuoteMeta() { - fmt.Println(regexp.QuoteMeta("Escaping symbols like: .+*?()|[]{}^$")) + fmt.Println(regexp.QuoteMeta(`Escaping symbols like: .+*?()|[]{}^$`)) // Output: // Escaping symbols like: \.\+\*\?\(\)\|\[\]\{\}\^\$ } +func ExampleRegexp_Find() { + re := regexp.MustCompile(`foo.?`) + fmt.Printf("%q\n", re.Find([]byte(`seafood fool`))) + + // Output: + // "food" +} + +func ExampleRegexp_FindAll() { + re := regexp.MustCompile(`foo.?`) + fmt.Printf("%q\n", re.FindAll([]byte(`seafood fool`), -1)) + + // Output: + // ["food" "fool"] +} + +func ExampleRegexp_FindAllSubmatch() { + re := regexp.MustCompile(`foo(.?)`) + fmt.Printf("%q\n", re.FindAllSubmatch([]byte(`seafood fool`), -1)) + + // Output: + // [["food" "d"] ["fool" "l"]] +} + +func ExampleRegexp_FindSubmatch() { + re := regexp.MustCompile(`foo(.?)`) + fmt.Printf("%q\n", re.FindSubmatch([]byte(`seafood fool`))) + + // Output: + // ["food" "d"] +} + +func ExampleRegexp_Match() { + re := regexp.MustCompile(`foo.?`) + fmt.Println(re.Match([]byte(`seafood fool`))) + + // Output: + // true +} + func ExampleRegexp_FindString() { - re := regexp.MustCompile("foo.?") + re := regexp.MustCompile(`foo.?`) fmt.Printf("%q\n", re.FindString("seafood fool")) fmt.Printf("%q\n", re.FindString("meat")) // Output: @@ -54,7 +108,7 @@ func ExampleRegexp_FindString() { } func ExampleRegexp_FindStringIndex() { - re := regexp.MustCompile("ab?") + re := regexp.MustCompile(`ab?`) fmt.Println(re.FindStringIndex("tablett")) fmt.Println(re.FindStringIndex("foo") == nil) // Output: @@ -63,7 +117,7 @@ func ExampleRegexp_FindStringIndex() { } func ExampleRegexp_FindStringSubmatch() { - re := regexp.MustCompile("a(x*)b(y|z)c") + re := regexp.MustCompile(`a(x*)b(y|z)c`) fmt.Printf("%q\n", re.FindStringSubmatch("-axxxbyc-")) fmt.Printf("%q\n", re.FindStringSubmatch("-abzc-")) // Output: @@ -72,7 +126,7 @@ func ExampleRegexp_FindStringSubmatch() { } func ExampleRegexp_FindAllString() { - re := regexp.MustCompile("a.") + re := regexp.MustCompile(`a.`) fmt.Println(re.FindAllString("paranormal", -1)) fmt.Println(re.FindAllString("paranormal", 2)) fmt.Println(re.FindAllString("graal", -1)) @@ -85,7 +139,7 @@ func ExampleRegexp_FindAllString() { } func ExampleRegexp_FindAllStringSubmatch() { - re := regexp.MustCompile("a(x*)b") + re := regexp.MustCompile(`a(x*)b`) fmt.Printf("%q\n", re.FindAllStringSubmatch("-ab-", -1)) fmt.Printf("%q\n", re.FindAllStringSubmatch("-axxb-", -1)) fmt.Printf("%q\n", re.FindAllStringSubmatch("-ab-axb-", -1)) @@ -98,7 +152,7 @@ func ExampleRegexp_FindAllStringSubmatch() { } func ExampleRegexp_FindAllStringSubmatchIndex() { - re := regexp.MustCompile("a(x*)b") + re := regexp.MustCompile(`a(x*)b`) // Indices: // 01234567 012345678 // -ab-axb- -axxb-ab- @@ -116,7 +170,7 @@ func ExampleRegexp_FindAllStringSubmatchIndex() { } func ExampleRegexp_MatchString() { - re := regexp.MustCompile("(gopher){2}") + re := regexp.MustCompile(`(gopher){2}`) fmt.Println(re.MatchString("gopher")) fmt.Println(re.MatchString("gophergopher")) fmt.Println(re.MatchString("gophergophergopher")) @@ -127,7 +181,7 @@ func ExampleRegexp_MatchString() { } func ExampleRegexp_ReplaceAllLiteralString() { - re := regexp.MustCompile("a(x*)b") + re := regexp.MustCompile(`a(x*)b`) fmt.Println(re.ReplaceAllLiteralString("-ab-axxb-", "T")) fmt.Println(re.ReplaceAllLiteralString("-ab-axxb-", "$1")) fmt.Println(re.ReplaceAllLiteralString("-ab-axxb-", "${1}")) @@ -138,7 +192,7 @@ func ExampleRegexp_ReplaceAllLiteralString() { } func ExampleRegexp_ReplaceAllString() { - re := regexp.MustCompile("a(x*)b") + re := regexp.MustCompile(`a(x*)b`) fmt.Println(re.ReplaceAllString("-ab-axxb-", "T")) fmt.Println(re.ReplaceAllString("-ab-axxb-", "$1")) fmt.Println(re.ReplaceAllString("-ab-axxb-", "$1W")) @@ -151,7 +205,7 @@ func ExampleRegexp_ReplaceAllString() { } func ExampleRegexp_SubexpNames() { - re := regexp.MustCompile("(?P [a-zA-Z]+) (?P [a-zA-Z]+)") + re := regexp.MustCompile(`(?P [a-zA-Z]+) (?P [a-zA-Z]+)`) fmt.Println(re.MatchString("Alan Turing")) fmt.Printf("%q\n", re.SubexpNames()) reversed := fmt.Sprintf("${%s} ${%s}", re.SubexpNames()[2], re.SubexpNames()[1]) @@ -165,12 +219,12 @@ func ExampleRegexp_SubexpNames() { } func ExampleRegexp_Split() { - a := regexp.MustCompile("a") + a := regexp.MustCompile(`a`) fmt.Println(a.Split("banana", -1)) fmt.Println(a.Split("banana", 0)) fmt.Println(a.Split("banana", 1)) fmt.Println(a.Split("banana", 2)) - zp := regexp.MustCompile("z+") + zp := regexp.MustCompile(`z+`) fmt.Println(zp.Split("pizza", -1)) fmt.Println(zp.Split("pizza", 0)) fmt.Println(zp.Split("pizza", 1)) diff --git a/src/run.bash b/src/run.bash index c14f4a206d3f3d..1c6c4244349f55 100755 --- a/src/run.bash +++ b/src/run.bash @@ -21,6 +21,7 @@ export GOPATH unset CDPATH # in case user has it set unset GOBIN # Issue 14340 unset GOFLAGS +unset GO111MODULE export GOHOSTOS export CC diff --git a/src/run.bat b/src/run.bat index 0e0c413617c765..123edcc35dd7d6 100644 --- a/src/run.bat +++ b/src/run.bat @@ -18,6 +18,7 @@ set GOPATH= :: Issue 14340: ignore GOBIN during all.bat. set GOBIN= set GOFLAGS= +set GO111MODULE= rem TODO avoid rebuild if possible diff --git a/src/run.rc b/src/run.rc index 49d6fd9a4df1e6..c346f5cf5c6a27 100755 --- a/src/run.rc +++ b/src/run.rc @@ -11,5 +11,6 @@ GOPATH = () # we disallow local import for non-local packages, if $GOROOT happen # to be under $GOPATH, then some tests below will fail GOBIN = () # Issue 14340 GOFLAGS = () +GO111MODULE = () exec go tool dist test -rebuild $* diff --git a/src/runtime/asm_arm64.s b/src/runtime/asm_arm64.s index 28d3077b9dea0b..bbeb3df0c85f57 100644 --- a/src/runtime/asm_arm64.s +++ b/src/runtime/asm_arm64.s @@ -18,7 +18,6 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0 // create istack out of the given (operating system) stack. // _cgo_init may update stackguard. MOVD $runtime·g0(SB), g - BL runtime·save_g(SB) MOVD RSP, R7 MOVD $(-64*1024)(R7), R0 MOVD R0, g_stackguard0(g) @@ -45,6 +44,7 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0 ADD $16, RSP nocgo: + BL runtime·save_g(SB) // update stackguard after _cgo_init MOVD (g_stack+stack_lo)(g), R0 ADD $const__StackGuard, R0 diff --git a/src/runtime/asm_ppc64x.s b/src/runtime/asm_ppc64x.s index fb0003c9b2f928..0a89b57cd81bae 100644 --- a/src/runtime/asm_ppc64x.s +++ b/src/runtime/asm_ppc64x.s @@ -36,6 +36,12 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0 MOVD _cgo_init(SB), R12 CMP R0, R12 BEQ nocgo +#ifdef GOARCH_ppc64 + // ppc64 use elf ABI v1. we must get the real entry address from + // first slot of the function descriptor before call. + MOVD 8(R12), R2 + MOVD (R12), R12 +#endif MOVD R12, CTR // r12 = "global function entry point" MOVD R13, R5 // arg 2: TLS base pointer MOVD $setg_gcc<>(SB), R4 // arg 1: setg @@ -597,6 +603,16 @@ g0: #endif // This is a "global call", so put the global entry point in r12 MOVD R3, R12 + +#ifdef GOARCH_ppc64 + // ppc64 use elf ABI v1. we must get the real entry address from + // first slot of the function descriptor before call. +#ifndef GOOS_aix + // aix just passes the function pointer for the moment, see golang.org/cl/146898 for details. + MOVD 8(R12), R2 + MOVD (R12), R12 +#endif +#endif MOVD R12, CTR MOVD R4, R3 // arg in r3 BL (CTR) @@ -754,9 +770,20 @@ TEXT runtime·setg(SB), NOSPLIT, $0-8 BL runtime·save_g(SB) RET +#ifdef GOARCH_ppc64 +TEXT setg_gcc<>(SB),NOSPLIT|NOFRAME,$0-0 + DWORD $_setg_gcc<>(SB) + DWORD $0 + DWORD $0 +#endif + // void setg_gcc(G*); set g in C TLS. // Must obey the gcc calling convention. +#ifdef GOARCH_ppc64le TEXT setg_gcc<>(SB),NOSPLIT|NOFRAME,$0-0 +#else +TEXT _setg_gcc<>(SB),NOSPLIT|NOFRAME,$0-0 +#endif // The standard prologue clobbers R31, which is callee-save in // the C ABI, so we have to use $-8-0 and save LR ourselves. MOVD LR, R4 diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 12fa744052acc0..e827dbae93d5b5 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -641,6 +641,27 @@ mapped: } } + // Add the arena to the arenas list. + if len(h.allArenas) == cap(h.allArenas) { + size := 2 * uintptr(cap(h.allArenas)) * sys.PtrSize + if size == 0 { + size = physPageSize + } + newArray := (*notInHeap)(persistentalloc(size, sys.PtrSize, &memstats.gc_sys)) + if newArray == nil { + throw("out of memory allocating allArenas") + } + oldSlice := h.allArenas + *(*notInHeapSlice)(unsafe.Pointer(&h.allArenas)) = notInHeapSlice{newArray, len(h.allArenas), int(size / sys.PtrSize)} + copy(h.allArenas, oldSlice) + // Do not free the old backing array because + // there may be concurrent readers. Since we + // double the array each time, this can lead + // to at most 2x waste. + } + h.allArenas = h.allArenas[:len(h.allArenas)+1] + h.allArenas[len(h.allArenas)-1] = ri + // Store atomically just in case an object from the // new heap arena becomes visible before the heap lock // is released (which shouldn't happen, but there's diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index f4646db67aac5f..2c7dd85b243c2c 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -1974,6 +1974,9 @@ func gcSweep(mode gcMode) { throw("non-empty swept list") } mheap_.pagesSwept = 0 + mheap_.sweepArenas = mheap_.allArenas + mheap_.reclaimIndex = 0 + mheap_.reclaimCredit = 0 unlock(&mheap_.lock) if !_ConcurrentSweep || mode == gcForceBlockMode { @@ -2023,6 +2026,18 @@ func gcResetMarkState() { } unlock(&allglock) + // Clear page marks. This is just 1MB per 64GB of heap, so the + // time here is pretty trivial. + lock(&mheap_.lock) + arenas := mheap_.allArenas + unlock(&mheap_.lock) + for _, ai := range arenas { + ha := mheap_.arenas[ai.l1()][ai.l2()] + for i := range ha.pageMarks { + ha.pageMarks[i] = 0 + } + } + work.bytesMarked = 0 work.initialHeapLive = atomic.Load64(&memstats.heap_live) } diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go index 28260ab7060bb8..03c64c4b113752 100644 --- a/src/runtime/mgcmark.go +++ b/src/runtime/mgcmark.go @@ -1229,6 +1229,13 @@ func greyobject(obj, base, off uintptr, span *mspan, gcw *gcWork, objIndex uintp return } mbits.setMarked() + + // Mark span. + arena, pageIdx, pageMask := pageIndexOf(span.base()) + if arena.pageMarks[pageIdx]&pageMask == 0 { + atomic.Or8(&arena.pageMarks[pageIdx], pageMask) + } + // If this is a noscan object, fast-track it to black // instead of greying it. if span.spanclass.noscan() { diff --git a/src/runtime/mgcsweep.go b/src/runtime/mgcsweep.go index 6733aa9b4a8aa1..edb9fcac09026b 100644 --- a/src/runtime/mgcsweep.go +++ b/src/runtime/mgcsweep.go @@ -4,6 +4,24 @@ // Garbage collector: sweeping +// The sweeper consists of two different algorithms: +// +// * The object reclaimer finds and frees unmarked slots in spans. It +// can free a whole span if none of the objects are marked, but that +// isn't its goal. This can be driven either synchronously by +// mcentral.cacheSpan for mcentral spans, or asynchronously by +// sweepone from the list of all in-use spans in mheap_.sweepSpans. +// +// * The span reclaimer looks for spans that contain no marked objects +// and frees whole spans. This is a separate algorithm because +// freeing whole spans is the hardest task for the object reclaimer, +// but is critical when allocating new spans. The entry point for +// this is mheap_.reclaim and it's driven by a sequential scan of +// the page marks bitmap in the heap arenas. +// +// Both algorithms ultimately call mspan.sweep, which sweeps a single +// heap span. + package runtime import ( @@ -72,7 +90,7 @@ func bgsweep(c chan int) { } } -// sweepone sweeps one span and returns the number of pages returned +// sweepone sweeps some unswept heap span and returns the number of pages returned // to the heap, or ^uintptr(0) if there was nothing to sweep. func sweepone() uintptr { _g_ := getg() @@ -115,7 +133,12 @@ func sweepone() uintptr { npages := ^uintptr(0) if s != nil { npages = s.npages - if !s.sweep(false) { + if s.sweep(false) { + // Whole span was freed. Count it toward the + // page reclaimer credit since these pages can + // now be used for span allocation. + atomic.Xadduintptr(&mheap_.reclaimCredit, npages) + } else { // Span is still in-use, so this returned no // pages to the heap and the span needs to // move to the swept in-use list. diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go index 97a0448ad32d6f..99994593c39349 100644 --- a/src/runtime/mheap.go +++ b/src/runtime/mheap.go @@ -30,12 +30,11 @@ const minPhysPageSize = 4096 //go:notinheap type mheap struct { lock mutex - free mTreap // free and non-scavenged spans - scav mTreap // free and scavenged spans - busy mSpanList // busy list of spans - sweepgen uint32 // sweep generation, see comment in mspan - sweepdone uint32 // all spans are swept - sweepers uint32 // number of active sweepone calls + free mTreap // free and non-scavenged spans + scav mTreap // free and scavenged spans + sweepgen uint32 // sweep generation, see comment in mspan + sweepdone uint32 // all spans are swept + sweepers uint32 // number of active sweepone calls // allspans is a slice of all mspans ever created. Each mspan // appears exactly once. @@ -89,6 +88,25 @@ type mheap struct { // TODO(austin): pagesInUse should be a uintptr, but the 386 // compiler can't 8-byte align fields. + // Page reclaimer state + + // reclaimIndex is the page index in allArenas of next page to + // reclaim. Specifically, it refers to page (i % + // pagesPerArena) of arena allArenas[i / pagesPerArena]. + // + // If this is >= 1<<63, the page reclaimer is done scanning + // the page marks. + // + // This is accessed atomically. + reclaimIndex uint64 + // reclaimCredit is spare credit for extra pages swept. Since + // the page reclaimer works in large chunks, it may reclaim + // more than requested. Any spare pages released go to this + // credit pool. + // + // This is accessed atomically. + reclaimCredit uintptr + // Malloc stats. largealloc uint64 // bytes allocated for large objects nlargealloc uint64 // number of large object allocations @@ -133,7 +151,21 @@ type mheap struct { // (the actual arenas). This is only used on 32-bit. arena linearAlloc - // _ uint32 // ensure 64-bit alignment of central + // allArenas is the arenaIndex of every mapped arena. This can + // be used to iterate through the address space. + // + // Access is protected by mheap_.lock. However, since this is + // append-only and old backing arrays are never freed, it is + // safe to acquire mheap_.lock, copy the slice header, and + // then release mheap_.lock. + allArenas []arenaIdx + + // sweepArenas is a snapshot of allArenas taken at the + // beginning of the sweep cycle. This can be read safely by + // simply blocking GC (by disabling preemption). + sweepArenas []arenaIdx + + _ uint32 // ensure 64-bit alignment of central // central free lists for small size classes. // the padding makes sure that the mcentrals are @@ -184,6 +216,29 @@ type heapArena struct { // must not be a safe-point between establishing that an // address is live and looking it up in the spans array. spans [pagesPerArena]*mspan + + // pageInUse is a bitmap that indicates which spans are in + // state mSpanInUse. This bitmap is indexed by page number, + // but only the bit corresponding to the first page in each + // span is used. + // + // Writes are protected by mheap_.lock. + pageInUse [pagesPerArena / 8]uint8 + + // pageMarks is a bitmap that indicates which spans have any + // marked objects on them. Like pageInUse, only the bit + // corresponding to the first page in each span is used. + // + // Writes are done atomically during marking. Reads are + // non-atomic and lock-free since they only occur during + // sweeping (and hence never race with writes). + // + // This is used to quickly find whole spans that can be freed. + // + // TODO(austin): It would be nice if this was uint64 for + // faster scanning, but we don't have 64-bit atomic bit + // operations. + pageMarks [pagesPerArena / 8]uint8 } // arenaHint is a hint for where to grow the heap arenas. See @@ -591,6 +646,16 @@ func spanOfHeap(p uintptr) *mspan { return s } +// pageIndexOf returns the arena, page index, and page mask for pointer p. +// The caller must ensure p is in the heap. +func pageIndexOf(p uintptr) (arena *heapArena, pageIdx uintptr, pageMask uint8) { + ai := arenaIndex(p) + arena = mheap_.arenas[ai.l1()][ai.l2()] + pageIdx = ((p / pageSize) / 8) % uintptr(len(arena.pageInUse)) + pageMask = byte(1 << ((p / pageSize) % 8)) + return +} + // Initialize the heap. func (h *mheap) init() { h.treapalloc.init(unsafe.Sizeof(treapNode{}), nil, nil, &memstats.other_sys) @@ -610,67 +675,164 @@ func (h *mheap) init() { h.spanalloc.zero = false // h->mapcache needs no init - h.busy.init() + for i := range h.central { h.central[i].mcentral.init(spanClass(i)) } } -// Sweeps spans in list until reclaims at least npages into heap. -// Returns the actual number of pages reclaimed. -func (h *mheap) reclaimList(list *mSpanList, npages uintptr) uintptr { - n := uintptr(0) - sg := mheap_.sweepgen -retry: - for s := list.first; s != nil; s = s.next { - if s.sweepgen == sg-2 && atomic.Cas(&s.sweepgen, sg-2, sg-1) { - list.remove(s) - // swept spans are at the end of the list - list.insertBack(s) // Puts it back on a busy list. s is not in the treap at this point. - unlock(&h.lock) - snpages := s.npages - if s.sweep(false) { - n += snpages +// reclaim sweeps and reclaims at least npage pages into the heap. +// It is called before allocating npage pages to keep growth in check. +// +// reclaim implements the page-reclaimer half of the sweeper. +// +// h must NOT be locked. +func (h *mheap) reclaim(npage uintptr) { + // This scans pagesPerChunk at a time. Higher values reduce + // contention on h.reclaimPos, but increase the minimum + // latency of performing a reclaim. + // + // Must be a multiple of the pageInUse bitmap element size. + // + // The time required by this can vary a lot depending on how + // many spans are actually freed. Experimentally, it can scan + // for pages at ~300 GB/ms on a 2.6GHz Core i7, but can only + // free spans at ~32 MB/ms. Using 512 pages bounds this at + // roughly 100µs. + // + // TODO(austin): Half of the time spent freeing spans is in + // locking/unlocking the heap (even with low contention). We + // could make the slow path here several times faster by + // batching heap frees. + const pagesPerChunk = 512 + + // Bail early if there's no more reclaim work. + if atomic.Load64(&h.reclaimIndex) >= 1<<63 { + return + } + + // Disable preemption so the GC can't start while we're + // sweeping, so we can read h.sweepArenas, and so + // traceGCSweepStart/Done pair on the P. + mp := acquirem() + + if trace.enabled { + traceGCSweepStart() + } + + arenas := h.sweepArenas + locked := false + for npage > 0 { + // Pull from accumulated credit first. + if credit := atomic.Loaduintptr(&h.reclaimCredit); credit > 0 { + take := credit + if take > npage { + // Take only what we need. + take = npage } - lock(&h.lock) - if n >= npages { - return n + if atomic.Casuintptr(&h.reclaimCredit, credit, credit-take) { + npage -= take } - // the span could have been moved elsewhere - goto retry - } - if s.sweepgen == sg-1 { - // the span is being swept by background sweeper, skip continue } - // already swept empty span, - // all subsequent ones must also be either swept or in process of sweeping - break + + // Claim a chunk of work. + idx := uintptr(atomic.Xadd64(&h.reclaimIndex, pagesPerChunk) - pagesPerChunk) + if idx/pagesPerArena >= uintptr(len(arenas)) { + // Page reclaiming is done. + atomic.Store64(&h.reclaimIndex, 1<<63) + break + } + + if !locked { + // Lock the heap for reclaimChunk. + lock(&h.lock) + locked = true + } + + // Scan this chunk. + nfound := h.reclaimChunk(arenas, idx, pagesPerChunk) + if nfound <= npage { + npage -= nfound + } else { + // Put spare pages toward global credit. + atomic.Xadduintptr(&h.reclaimCredit, nfound-npage) + npage = 0 + } + } + if locked { + unlock(&h.lock) } - return n -} -// Sweeps and reclaims at least npage pages into heap. -// Called before allocating npage pages. -func (h *mheap) reclaim(npage uintptr) { - if h.reclaimList(&h.busy, npage) != 0 { - return // Bingo! + if trace.enabled { + traceGCSweepDone() } + releasem(mp) +} - // Now sweep everything that is not yet swept. - var reclaimed uintptr - unlock(&h.lock) - for { - n := sweepone() - if n == ^uintptr(0) { // all spans are swept - break +// reclaimChunk sweeps unmarked spans that start at page indexes [pageIdx, pageIdx+n). +// It returns the number of pages returned to the heap. +// +// h.lock must be held and the caller must be non-preemptible. +func (h *mheap) reclaimChunk(arenas []arenaIdx, pageIdx, n uintptr) uintptr { + // The heap lock must be held because this accesses the + // heapArena.spans arrays using potentially non-live pointers. + // In particular, if a span were freed and merged concurrently + // with this probing heapArena.spans, it would be possible to + // observe arbitrary, stale span pointers. + n0 := n + var nFreed uintptr + sg := h.sweepgen + for n > 0 { + ai := arenas[pageIdx/pagesPerArena] + ha := h.arenas[ai.l1()][ai.l2()] + + // Get a chunk of the bitmap to work on. + arenaPage := uint(pageIdx % pagesPerArena) + inUse := ha.pageInUse[arenaPage/8:] + marked := ha.pageMarks[arenaPage/8:] + if uintptr(len(inUse)) > n/8 { + inUse = inUse[:n/8] + marked = marked[:n/8] } - reclaimed += n - if reclaimed >= npage { - break + + // Scan this bitmap chunk for spans that are in-use + // but have no marked objects on them. + for i := range inUse { + inUseUnmarked := inUse[i] &^ marked[i] + if inUseUnmarked == 0 { + continue + } + + for j := uint(0); j < 8; j++ { + if inUseUnmarked&(1< (SB) + DWORD $0 + DWORD $0 + TEXT _main<>(SB),NOSPLIT,$-8 // In a statically linked binary, the stack contains argc, // argv as argc string pointers followed by a NULL, envv as a @@ -13,11 +18,13 @@ TEXT _main<>(SB),NOSPLIT,$-8 // There is no TLS base pointer. // // TODO(austin): Support ABI v1 dynamic linking entry point - MOVD 0(R1), R3 // argc - ADD $8, R1, R4 // argv - BR main(SB) - -TEXT main(SB),NOSPLIT,$-8 MOVD $runtime·rt0_go(SB), R12 MOVD R12, CTR + MOVBZ runtime·iscgo(SB), R5 + CMP R5, $0 + BEQ nocgo + BR (CTR) +nocgo: + MOVD 0(R1), R3 // argc + ADD $8, R1, R4 // argv BR (CTR) diff --git a/src/runtime/sys_linux_ppc64x.s b/src/runtime/sys_linux_ppc64x.s index bf01099830799c..6835f434de4fca 100644 --- a/src/runtime/sys_linux_ppc64x.s +++ b/src/runtime/sys_linux_ppc64x.s @@ -414,7 +414,7 @@ TEXT runtime·cgoSigtramp(SB),NOSPLIT|NOFRAME,$0 DWORD $0 DWORD $0 TEXT runtime·_cgoSigtramp(SB),NOSPLIT,$0 - JMP runtime·sigtramp(SB) + JMP runtime·_sigtramp(SB) #endif TEXT runtime·sigprofNonGoWrapper<>(SB),NOSPLIT,$0 diff --git a/src/syscall/js/js.go b/src/syscall/js/js.go index 19cdedc309ad6e..885723f87d690b 100644 --- a/src/syscall/js/js.go +++ b/src/syscall/js/js.go @@ -114,6 +114,8 @@ func Global() Value { // | string | string | // | []interface{} | new array | // | map[string]interface{} | new object | +// +// Panics if x is not one of the expected types. func ValueOf(x interface{}) Value { switch x := x.(type) { case Value: // should precede Wrapper to avoid a loop diff --git a/src/syscall/syscall_js.go b/src/syscall/syscall_js.go index 6822eec8359cab..2e1a9ec9f1fef0 100644 --- a/src/syscall/syscall_js.go +++ b/src/syscall/syscall_js.go @@ -74,6 +74,7 @@ const ( SIGKILL SIGTRAP SIGQUIT + SIGTERM ) func (s Signal) Signal() {} diff --git a/src/testing/testing.go b/src/testing/testing.go index 0bc222c0bb3387..0ac51b6fe51625 100644 --- a/src/testing/testing.go +++ b/src/testing/testing.go @@ -17,13 +17,13 @@ // package builds but will be included when the ``go test'' command is run. // For more detail, run ``go help test'' and ``go help testflag''. // -// Tests and benchmarks may be skipped if not applicable with a call to -// the Skip method of *T and *B: -// func TestTimeConsuming(t *testing.T) { -// if testing.Short() { -// t.Skip("skipping test in short mode.") +// A simple test function looks like this: +// +// func TestAbs(t *testing.T) { +// got := Abs(-1) +// if got != 1 { +// t.Errorf("Abs(-1) = %d; want 1", got) // } -// ... // } // // Benchmarks @@ -132,6 +132,18 @@ // example function, at least one other function, type, variable, or constant // declaration, and no test or benchmark functions. // +// Skipping +// +// Tests or benchmarks may be skipped at run time with a call to +// the Skip method of *T or *B: +// +// func TestTimeConsuming(t *testing.T) { +// if testing.Short() { +// t.Skip("skipping test in short mode.") +// } +// ... +// } +// // Subtests and Sub-benchmarks // // The Run methods of T and B allow defining subtests and sub-benchmarks, diff --git a/src/vendor/golang_org/x/net/route/empty.s b/src/vendor/golang_org/x/net/route/empty.s new file mode 100644 index 00000000000000..bff0231c7d57ea --- /dev/null +++ b/src/vendor/golang_org/x/net/route/empty.s @@ -0,0 +1,7 @@ +// 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,go1.12 + +// This exists solely so we can linkname in symbols from syscall. diff --git a/src/vendor/golang_org/x/net/route/syscall.go b/src/vendor/golang_org/x/net/route/syscall.go index 5f69ea63d91e1c..72431b03410614 100644 --- a/src/vendor/golang_org/x/net/route/syscall.go +++ b/src/vendor/golang_org/x/net/route/syscall.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin dragonfly freebsd netbsd openbsd +// +build dragonfly freebsd netbsd openbsd package route diff --git a/src/vendor/golang_org/x/net/route/syscall_go1_11_darwin.go b/src/vendor/golang_org/x/net/route/syscall_go1_11_darwin.go new file mode 100644 index 00000000000000..7228e443cd23f8 --- /dev/null +++ b/src/vendor/golang_org/x/net/route/syscall_go1_11_darwin.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 !go1.12 + +package route + +import ( + "syscall" + "unsafe" +) + +var zero uintptr + +func sysctl(mib []int32, old *byte, oldlen *uintptr, new *byte, newlen uintptr) error { + var p unsafe.Pointer + if len(mib) > 0 { + p = unsafe.Pointer(&mib[0]) + } else { + p = unsafe.Pointer(&zero) + } + _, _, errno := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(p), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), newlen) + if errno != 0 { + return error(errno) + } + return nil +} diff --git a/src/vendor/golang_org/x/net/route/syscall_go1_12_darwin.go b/src/vendor/golang_org/x/net/route/syscall_go1_12_darwin.go new file mode 100644 index 00000000000000..7922a6836fc3da --- /dev/null +++ b/src/vendor/golang_org/x/net/route/syscall_go1_12_darwin.go @@ -0,0 +1,12 @@ +// 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 go1.12 + +package route + +import _ "unsafe" // for linkname + +//go:linkname sysctl syscall.sysctl +func sysctl(mib []int32, old *byte, oldlen *uintptr, new *byte, newlen uintptr) error diff --git a/test/run.go b/test/run.go index 3a9e267940f250..39647d7252d15f 100644 --- a/test/run.go +++ b/test/run.go @@ -813,7 +813,7 @@ func (t *test) run() { t.err = fmt.Errorf("write empty go_asm.h: %s", err) return } - cmd := []string{goTool(), "tool", "asm", "-symabis", "-o", "symabis"} + cmd := []string{goTool(), "tool", "asm", "-gensymabis", "-o", "symabis"} cmd = append(cmd, asms...) _, err = runcmd(cmd...) if err != nil {