Merge branch 'master' into ref-chan.go

This commit is contained in:
Pouriya 2024-02-28 01:17:53 +03:30 committed by GitHub
commit f97fe5b5bf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
359 changed files with 4446 additions and 2800 deletions

1
api/next/57151.txt Normal file
View file

@ -0,0 +1 @@
pkg path/filepath, func Localize(string) (string, error) #57151

1
api/next/62484.txt Normal file
View file

@ -0,0 +1 @@
pkg os, func CopyFS(string, fs.FS) error #62484

View file

@ -2,5 +2,11 @@
### Go command {#go-command}
Setting the `GOROOT_FINAL` environment variable no longer has an effect
([#62047](https://go.dev/issue/62047)).
Distributions that install the `go` command to a location other than
`$GOROOT/bin/go` should install a symlink instead of relocating
or copying the `go` binary.
### Cgo {#cgo}

View file

@ -1,4 +1,4 @@
The new type [`KeepAliveConfig`](/net#KeepAliveConfig) permits fine-tuning
the keep-alive options for TCP connections, via a new
[`TCPConn.SetKeepAliveConfig`](/net#TCPConn.SetKeepAliveConfig) method and
new KeepAliveConfig fields for [`Dialer`](net#Dialer) and [`ListenConfig`](net#ListenConfig).
new KeepAliveConfig fields for [`Dialer`](/net#Dialer) and [`ListenConfig`](/net#ListenConfig).

View file

@ -0,0 +1,2 @@
The patterns used by [`net/http.ServeMux`](//net/http#ServeMux) allow
multiple spaces matching regexp '[ \t]+'.

View file

@ -0,0 +1,3 @@
The [`os.Stat`](/os#Stat) function now sets the [`os.ModeSocket`](/os#ModeSocket)
bit for files that are Unix sockets on Windows. These files are identified by
having a reparse tag set to `IO_REPARSE_TAG_AF_UNIX`.

View file

@ -0,0 +1,2 @@
The [`CopyFS`](/os#CopyFS) function copies an [`io/fs.FS`](/io/fs#FS)
into the local filesystem.

View file

@ -0,0 +1,2 @@
The new [`Localize`](/path/filepath#Localize) function safely converts
a slash-separated path into an operating system path.

View file

@ -1 +0,0 @@
See `syscall (windows-386)/62254.md`.

View file

@ -581,10 +581,10 @@ func TestPaxSymlink(t *testing.T) {
t.Fatal(err)
}
hdr, err := FileInfoHeader(fileinfo, "")
hdr.Typeflag = TypeSymlink
if err != nil {
t.Fatalf("os.Stat:1 %v", err)
}
hdr.Typeflag = TypeSymlink
// Force a PAX long linkname to be written
longLinkname := strings.Repeat("1234567890/1234567890", 10)
hdr.Linkname = longLinkname
@ -761,10 +761,10 @@ func TestUSTARLongName(t *testing.T) {
t.Fatal(err)
}
hdr, err := FileInfoHeader(fileinfo, "")
hdr.Typeflag = TypeDir
if err != nil {
t.Fatalf("os.Stat:1 %v", err)
}
hdr.Typeflag = TypeDir
// Force a PAX long name to be written. The name was taken from a practical example
// that fails and replaced ever char through numbers to anonymize the sample.
longName := "/0000_0000000/00000-000000000/0000_0000000/00000-0000000000000/0000_0000000/00000-0000000-00000000/0000_0000000/00000000/0000_0000000/000/0000_0000000/00000000v00/0000_0000000/000000/0000_0000000/0000000/0000_0000000/00000y-00/0000/0000/00000000/0x000000/"

View file

@ -109,32 +109,18 @@ func testAddr2Line(t *testing.T, dbgExePath, addr string) {
srcPath = filepath.FromSlash(srcPath)
fi2, err := os.Stat(srcPath)
// If GOROOT_FINAL is set and srcPath is not the file we expect, perhaps
// srcPath has had GOROOT_FINAL substituted for GOROOT and GOROOT hasn't been
// moved to its final location yet. If so, try the original location instead.
if gorootFinal := os.Getenv("GOROOT_FINAL"); gorootFinal != "" &&
(os.IsNotExist(err) || (err == nil && !os.SameFile(fi1, fi2))) {
// srcPath is clean, but GOROOT_FINAL itself might not be.
// (See https://golang.org/issue/41447.)
gorootFinal = filepath.Clean(gorootFinal)
if strings.HasPrefix(srcPath, gorootFinal) {
fi2, err = os.Stat(runtime.GOROOT() + strings.TrimPrefix(srcPath, gorootFinal))
}
}
if err != nil {
t.Fatalf("Stat failed: %v", err)
}
if !os.SameFile(fi1, fi2) {
t.Fatalf("addr2line_test.go and %s are not same file", srcPath)
}
if srcLineNo != "138" {
t.Fatalf("line number = %v; want 138", srcLineNo)
if want := "124"; srcLineNo != want {
t.Fatalf("line number = %v; want %s", srcLineNo, want)
}
}
// This is line 137. The test depends on that.
// This is line 123. The test depends on that.
func TestAddr2Line(t *testing.T) {
testenv.MustHaveGoBuild(t)

View file

@ -16,6 +16,7 @@ import (
"cmd/asm/internal/lex"
"cmd/internal/obj"
"cmd/internal/obj/ppc64"
"cmd/internal/obj/riscv"
"cmd/internal/obj/x86"
"cmd/internal/sys"
)
@ -46,7 +47,11 @@ func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) {
p.errorf("%v", err)
return
}
case sys.RISCV64:
if err := riscv.ParseSuffix(prog, cond); err != nil {
p.errorf("unrecognized suffix .%q", cond)
return
}
default:
p.errorf("unrecognized suffix .%q", cond)
return

View file

@ -217,8 +217,8 @@ next:
for {
tok = p.nextToken()
if len(operands) == 0 && len(items) == 0 {
if p.arch.InFamily(sys.ARM, sys.ARM64, sys.AMD64, sys.I386) && tok == '.' {
// Suffixes: ARM conditionals or x86 modifiers.
if p.arch.InFamily(sys.ARM, sys.ARM64, sys.AMD64, sys.I386, sys.RISCV64) && tok == '.' {
// Suffixes: ARM conditionals, RISCV rounding mode or x86 modifiers.
tok = p.nextToken()
str := p.lex.Text()
if tok != scanner.Ident {

View file

@ -233,11 +233,31 @@ start:
// 11.7: Single-Precision Floating-Point Conversion and Move Instructions
FCVTWS F0, X5 // d31200c0
FCVTWS.RNE F0, X5 // d30200c0
FCVTWS.RTZ F0, X5 // d31200c0
FCVTWS.RDN F0, X5 // d32200c0
FCVTWS.RUP F0, X5 // d33200c0
FCVTWS.RMM F0, X5 // d34200c0
FCVTLS F0, X5 // d31220c0
FCVTLS.RNE F0, X5 // d30220c0
FCVTLS.RTZ F0, X5 // d31220c0
FCVTLS.RDN F0, X5 // d32220c0
FCVTLS.RUP F0, X5 // d33220c0
FCVTLS.RMM F0, X5 // d34220c0
FCVTSW X5, F0 // 538002d0
FCVTSL X5, F0 // 538022d0
FCVTWUS F0, X5 // d31210c0
FCVTWUS.RNE F0, X5 // d30210c0
FCVTWUS.RTZ F0, X5 // d31210c0
FCVTWUS.RDN F0, X5 // d32210c0
FCVTWUS.RUP F0, X5 // d33210c0
FCVTWUS.RMM F0, X5 // d34210c0
FCVTLUS F0, X5 // d31230c0
FCVTLUS.RNE F0, X5 // d30230c0
FCVTLUS.RTZ F0, X5 // d31230c0
FCVTLUS.RDN F0, X5 // d32230c0
FCVTLUS.RUP F0, X5 // d33230c0
FCVTLUS.RMM F0, X5 // d34230c0
FCVTSWU X5, F0 // 538012d0
FCVTSLU X5, F0 // 538032d0
FSGNJS F1, F0, F2 // 53011020
@ -277,11 +297,31 @@ start:
// 12.5: Double-Precision Floating-Point Conversion and Move Instructions
FCVTWD F0, X5 // d31200c2
FCVTWD.RNE F0, X5 // d30200c2
FCVTWD.RTZ F0, X5 // d31200c2
FCVTWD.RDN F0, X5 // d32200c2
FCVTWD.RUP F0, X5 // d33200c2
FCVTWD.RMM F0, X5 // d34200c2
FCVTLD F0, X5 // d31220c2
FCVTLD.RNE F0, X5 // d30220c2
FCVTLD.RTZ F0, X5 // d31220c2
FCVTLD.RDN F0, X5 // d32220c2
FCVTLD.RUP F0, X5 // d33220c2
FCVTLD.RMM F0, X5 // d34220c2
FCVTDW X5, F0 // 538002d2
FCVTDL X5, F0 // 538022d2
FCVTWUD F0, X5 // d31210c2
FCVTWUD.RNE F0, X5 // d30210c2
FCVTWUD.RTZ F0, X5 // d31210c2
FCVTWUD.RDN F0, X5 // d32210c2
FCVTWUD.RUP F0, X5 // d33210c2
FCVTWUD.RMM F0, X5 // d34210c2
FCVTLUD F0, X5 // d31230c2
FCVTLUD.RNE F0, X5 // d30230c2
FCVTLUD.RTZ F0, X5 // d31230c2
FCVTLUD.RDN F0, X5 // d32230c2
FCVTLUD.RUP F0, X5 // d33230c2
FCVTLUD.RMM F0, X5 // d34230c2
FCVTDWU X5, F0 // 538012d2
FCVTDLU X5, F0 // 538032d2
FCVTSD F0, F1 // d3001040

View file

@ -0,0 +1,15 @@
// Copyright 2024 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.
//go:build (ppc64 || ppc64le) && internal
package cgotest
import "testing"
// If gcc is used, and linking internally, __mulsc3 and __muldc3
// will be linked in from libgcc which make several R_PPC64_TOC16_DS
// relocations which may not be resolvable with the internal linker.
func test8694(t *testing.T) { t.Skip("not supported on ppc64/ppc64le with internal linking") }
func test9510(t *testing.T) { t.Skip("not supported on ppc64/ppc64le with internal linking") }

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !android
//go:build !android && !((ppc64 || ppc64le) && internal)
package cgotest

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build cgo
//go:build cgo && !((ppc64 || ppc64le) && internal)
// Test that we can link together two different cgo packages that both
// use the same libgcc function.

View file

@ -218,10 +218,10 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir
}
typename := dwarf.InfoPrefix + types.TypeSymName(n.Type())
decls = append(decls, n)
abbrev := dwarf.DW_ABRV_AUTO_LOCLIST
tag := dwarf.DW_TAG_variable
isReturnValue := (n.Class == ir.PPARAMOUT)
if n.Class == ir.PPARAM || n.Class == ir.PPARAMOUT {
abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
tag = dwarf.DW_TAG_formal_parameter
}
if n.Esc() == ir.EscHeap {
// The variable in question has been promoted to the heap.
@ -233,7 +233,7 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir
if n.InlFormal() || n.InlLocal() {
inlIndex = posInlIndex(n.Pos()) + 1
if n.InlFormal() {
abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
tag = dwarf.DW_TAG_formal_parameter
}
}
}
@ -241,7 +241,8 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir
vars = append(vars, &dwarf.Var{
Name: n.Sym().Name,
IsReturnValue: isReturnValue,
Abbrev: abbrev,
Tag: tag,
WithLoclist: true,
StackOffset: int32(n.FrameOffset()),
Type: base.Ctxt.Lookup(typename),
DeclFile: declpos.RelFilename(),
@ -350,7 +351,7 @@ func createSimpleVars(fnsym *obj.LSym, apDecls []*ir.Name) ([]*ir.Name, []*dwarf
}
func createSimpleVar(fnsym *obj.LSym, n *ir.Name) *dwarf.Var {
var abbrev int
var tag int
var offs int64
localAutoOffset := func() int64 {
@ -367,9 +368,9 @@ func createSimpleVar(fnsym *obj.LSym, n *ir.Name) *dwarf.Var {
switch n.Class {
case ir.PAUTO:
offs = localAutoOffset()
abbrev = dwarf.DW_ABRV_AUTO
tag = dwarf.DW_TAG_variable
case ir.PPARAM, ir.PPARAMOUT:
abbrev = dwarf.DW_ABRV_PARAM
tag = dwarf.DW_TAG_formal_parameter
if n.IsOutputParamInRegisters() {
offs = localAutoOffset()
} else {
@ -387,7 +388,7 @@ func createSimpleVar(fnsym *obj.LSym, n *ir.Name) *dwarf.Var {
if n.InlFormal() || n.InlLocal() {
inlIndex = posInlIndex(n.Pos()) + 1
if n.InlFormal() {
abbrev = dwarf.DW_ABRV_PARAM
tag = dwarf.DW_TAG_formal_parameter
}
}
}
@ -396,7 +397,7 @@ func createSimpleVar(fnsym *obj.LSym, n *ir.Name) *dwarf.Var {
Name: n.Sym().Name,
IsReturnValue: n.Class == ir.PPARAMOUT,
IsInlFormal: n.InlFormal(),
Abbrev: abbrev,
Tag: tag,
StackOffset: int32(offs),
Type: base.Ctxt.Lookup(typename),
DeclFile: declpos.RelFilename(),
@ -470,12 +471,12 @@ func createComplexVar(fnsym *obj.LSym, fn *ir.Func, varID ssa.VarID) *dwarf.Var
debug := fn.DebugInfo.(*ssa.FuncDebug)
n := debug.Vars[varID]
var abbrev int
var tag int
switch n.Class {
case ir.PAUTO:
abbrev = dwarf.DW_ABRV_AUTO_LOCLIST
tag = dwarf.DW_TAG_variable
case ir.PPARAM, ir.PPARAMOUT:
abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
tag = dwarf.DW_TAG_formal_parameter
default:
return nil
}
@ -488,7 +489,7 @@ func createComplexVar(fnsym *obj.LSym, fn *ir.Func, varID ssa.VarID) *dwarf.Var
if n.InlFormal() || n.InlLocal() {
inlIndex = posInlIndex(n.Pos()) + 1
if n.InlFormal() {
abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
tag = dwarf.DW_TAG_formal_parameter
}
}
}
@ -497,7 +498,8 @@ func createComplexVar(fnsym *obj.LSym, fn *ir.Func, varID ssa.VarID) *dwarf.Var
Name: n.Sym().Name,
IsReturnValue: n.Class == ir.PPARAMOUT,
IsInlFormal: n.InlFormal(),
Abbrev: abbrev,
Tag: tag,
WithLoclist: true,
Type: base.Ctxt.Lookup(typename),
// The stack offset is used as a sorting key, so for decomposed
// variables just give it the first one. It's not used otherwise.

View file

@ -358,7 +358,7 @@ func dumpInlCalls(inlcalls dwarf.InlCalls) {
func dumpInlVars(dwvars []*dwarf.Var) {
for i, dwv := range dwvars {
typ := "local"
if dwv.Abbrev == dwarf.DW_ABRV_PARAM_LOCLIST || dwv.Abbrev == dwarf.DW_ABRV_PARAM {
if dwv.Tag == dwarf.DW_TAG_formal_parameter {
typ = "param"
}
ia := 0

View file

@ -3620,6 +3620,57 @@ func usedLocals(body []ir.Node) ir.NameSet {
}
// @@@ Method wrappers
//
// Here we handle constructing "method wrappers," alternative entry
// points that adapt methods to different calling conventions. Given a
// user-declared method "func (T) M(i int) bool { ... }", there are a
// few wrappers we may need to construct:
//
// - Implicit dereferencing. Methods declared with a value receiver T
// are also included in the method set of the pointer type *T, so
// we need to construct a wrapper like "func (recv *T) M(i int)
// bool { return (*recv).M(i) }".
//
// - Promoted methods. If struct type U contains an embedded field of
// type T or *T, we need to construct a wrapper like "func (recv U)
// M(i int) bool { return recv.T.M(i) }".
//
// - Method values. If x is an expression of type T, then "x.M" is
// roughly "tmp := x; func(i int) bool { return tmp.M(i) }".
//
// At call sites, we always prefer to call the user-declared method
// directly, if known, so wrappers are only needed for indirect calls
// (for example, interface method calls that can't be devirtualized).
// Consequently, we can save some compile time by skipping
// construction of wrappers that are never needed.
//
// Alternatively, because the linker doesn't care which compilation
// unit constructed a particular wrapper, we can instead construct
// them as needed. However, if a wrapper is needed in multiple
// downstream packages, we may end up needing to compile it multiple
// times, costing us more compile time and object file size. (We mark
// the wrappers as DUPOK, so the linker doesn't complain about the
// duplicate symbols.)
//
// The current heuristics we use to balance these trade offs are:
//
// - For a (non-parameterized) defined type T, we construct wrappers
// for *T and any promoted methods on T (and *T) in the same
// compilation unit as the type declaration.
//
// - For a parameterized defined type, we construct wrappers in the
// compilation units in which the type is instantiated. We
// similarly handle wrappers for anonymous types with methods and
// compilation units where their type literals appear in source.
//
// - Method value expressions are relatively uncommon, so we
// construct their wrappers in the compilation units that they
// appear in.
//
// Finally, as an opportunistic compile-time optimization, if we know
// a wrapper was constructed in any imported package's compilation
// unit, then we skip constructing a duplicate one. However, currently
// this is only done on a best-effort basis.
// needWrapperTypes lists types for which we may need to generate
// method wrappers.
@ -3643,6 +3694,8 @@ type methodValueWrapper struct {
method *types.Field
}
// needWrapper records that wrapper methods may be needed at link
// time.
func (r *reader) needWrapper(typ *types.Type) {
if typ.IsPtr() {
return
@ -3676,6 +3729,8 @@ func (r *reader) importedDef() bool {
return r.p != localPkgReader && !r.hasTypeParams()
}
// MakeWrappers constructs all wrapper methods needed for the target
// compilation unit.
func MakeWrappers(target *ir.Package) {
// always generate a wrapper for error.Error (#29304)
needWrapperTypes = append(needWrapperTypes, types.ErrorType)
@ -3811,7 +3866,6 @@ func wrapMethodValue(recvType *types.Type, method *types.Field, target *ir.Packa
func newWrapperFunc(pos src.XPos, sym *types.Sym, wrapper *types.Type, method *types.Field) *ir.Func {
sig := newWrapperType(wrapper, method)
fn := ir.NewFunc(pos, pos, sym, sig)
fn.DeclareParams(true)
fn.SetDupok(true) // TODO(mdempsky): Leave unset for local, non-generic wrappers?

View file

@ -1217,10 +1217,17 @@ func (w *writer) stmt(stmt syntax.Stmt) {
func (w *writer) stmts(stmts []syntax.Stmt) {
dead := false
w.Sync(pkgbits.SyncStmts)
for _, stmt := range stmts {
if dead {
// Any statements after a terminating statement are safe to
// omit, at least until the next labeled statement.
var lastLabel = -1
for i, stmt := range stmts {
if _, ok := stmt.(*syntax.LabeledStmt); ok {
lastLabel = i
}
}
for i, stmt := range stmts {
if dead && i > lastLabel {
// Any statements after a terminating and last label statement are safe to omit.
// Otherwise, code after label statement may refer to dead stmts between terminating
// and label statement, see issue #65593.
if _, ok := stmt.(*syntax.LabeledStmt); !ok {
continue
}

View file

@ -1498,39 +1498,6 @@ func (a typesByString) Less(i, j int) bool {
}
func (a typesByString) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
// maxPtrmaskBytes is the maximum length of a GC ptrmask bitmap,
// which holds 1-bit entries describing where pointers are in a given type.
// Above this length, the GC information is recorded as a GC program,
// which can express repetition compactly. In either form, the
// information is used by the runtime to initialize the heap bitmap,
// and for large types (like 128 or more words), they are roughly the
// same speed. GC programs are never much larger and often more
// compact. (If large arrays are involved, they can be arbitrarily
// more compact.)
//
// The cutoff must be large enough that any allocation large enough to
// use a GC program is large enough that it does not share heap bitmap
// bytes with any other objects, allowing the GC program execution to
// assume an aligned start and not use atomic operations. In the current
// runtime, this means all malloc size classes larger than the cutoff must
// be multiples of four words. On 32-bit systems that's 16 bytes, and
// all size classes >= 16 bytes are 16-byte aligned, so no real constraint.
// On 64-bit systems, that's 32 bytes, and 32-byte alignment is guaranteed
// for size classes >= 256 bytes. On a 64-bit system, 256 bytes allocated
// is 32 pointers, the bits for which fit in 4 bytes. So maxPtrmaskBytes
// must be >= 4.
//
// We used to use 16 because the GC programs do have some constant overhead
// to get started, and processing 128 pointers seems to be enough to
// amortize that overhead well.
//
// To make sure that the runtime's chansend can call typeBitsBulkBarrier,
// we raised the limit to 2048, so that even 32-bit systems are guaranteed to
// use bitmaps for objects up to 64 kB in size.
//
// Also known to reflect/type.go.
const maxPtrmaskBytes = 2048
// GCSym returns a data symbol containing GC information for type t, along
// with a boolean reporting whether the UseGCProg bit should be set in the
// type kind, and the ptrdata field to record in the reflect type information.
@ -1553,7 +1520,7 @@ func GCSym(t *types.Type) (lsym *obj.LSym, useGCProg bool, ptrdata int64) {
// When write is true, it writes the symbol data.
func dgcsym(t *types.Type, write bool) (lsym *obj.LSym, useGCProg bool, ptrdata int64) {
ptrdata = types.PtrDataSize(t)
if ptrdata/int64(types.PtrSize) <= maxPtrmaskBytes*8 {
if ptrdata/int64(types.PtrSize) <= abi.MaxPtrmaskBytes*8 {
lsym = dgcptrmask(t, write)
return
}

View file

@ -2131,8 +2131,8 @@ func logicFlags32(x int32) flagConstant {
func makeJumpTableSym(b *Block) *obj.LSym {
s := base.Ctxt.Lookup(fmt.Sprintf("%s.jump%d", b.Func.fe.Func().LSym.Name, b.ID))
s.Set(obj.AttrDuplicateOK, true)
s.Set(obj.AttrLocal, true)
// The jump table symbol is accessed only from the function symbol.
s.Set(obj.AttrStatic, true)
return s
}

View file

@ -267,7 +267,9 @@ func (p *parser) syntaxErrorAt(pos Pos, msg string) {
// determine token string
var tok string
switch p.tok {
case _Name, _Semi:
case _Name:
tok = "`" + p.lit + "'"
case _Semi:
tok = p.lit
case _Literal:
tok = "literal " + p.lit

View file

@ -6,4 +6,4 @@
// Line 9 must end in EOF for this test (no newline).
package e
func([<-chan<-[func /* ERROR unexpected u */ u){go
func([<-chan<-[func /* ERROR unexpected `u' */ u){go

View file

@ -7,7 +7,7 @@ package p
func _() {
_ = m[] // ERROR expected operand
_ = m[x,]
_ = m[x /* ERROR unexpected a */ a b c d]
_ = m[x /* ERROR unexpected `a' */ a b c d]
}
// test case from the issue

View file

@ -7,7 +7,7 @@ package p
// test case from issue
type _ interface{
m /* ERROR unexpected int in interface type; possibly missing semicolon or newline or } */ int
m /* ERROR unexpected `int' in interface type; possibly missing semicolon or newline or } */ int
}
// other cases where the fix for this issue affects the error message
@ -16,12 +16,12 @@ const (
x int = 10 /* ERROR unexpected literal "foo" in grouped declaration; possibly missing semicolon or newline or \) */ "foo"
)
var _ = []int{1, 2, 3 /* ERROR unexpected int in composite literal; possibly missing comma or } */ int }
var _ = []int{1, 2, 3 /* ERROR unexpected `int' in composite literal; possibly missing comma or } */ int }
type _ struct {
x y /* ERROR syntax error: unexpected comma in struct type; possibly missing semicolon or newline or } */ ,
}
func f(a, b c /* ERROR unexpected d in parameter list; possibly missing comma or \) */ d) {
f(a, b, c /* ERROR unexpected d in argument list; possibly missing comma or \) */ d)
func f(a, b c /* ERROR unexpected `d' in parameter list; possibly missing comma or \) */ d) {
f(a, b, c /* ERROR unexpected `d' in argument list; possibly missing comma or \) */ d)
}

View file

@ -13,5 +13,5 @@ type _ interface {
(int) | (string)
(int) | ~(string)
(/* ERROR unexpected ~ */ ~int)
(int /* ERROR unexpected \| */ | /* ERROR unexpected string */ string /* ERROR unexpected \) */ )
(int /* ERROR unexpected \| */ | /* ERROR unexpected `string' */ string /* ERROR unexpected \) */ )
}

View file

@ -0,0 +1,14 @@
// Copyright 2023 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 p
import (
"fmt"
)
func f() {
int status // ERROR syntax error: unexpected `status' at end of statement
fmt.Println(status)
}

View file

@ -621,19 +621,6 @@ func tcIndex(n *ir.IndexExpr) ir.Node {
return n
}
if !n.Bounded() && ir.IsConst(n.Index, constant.Int) {
x := n.Index.Val()
if constant.Sign(x) < 0 {
base.Errorf("invalid %s index %v (index must be non-negative)", why, n.Index)
} else if t.IsArray() && constant.Compare(x, token.GEQ, constant.MakeInt64(t.NumElem())) {
base.Errorf("invalid array index %v (out of bounds for %d-element array)", n.Index, t.NumElem())
} else if ir.IsConst(n.X, constant.String) && constant.Compare(x, token.GEQ, constant.MakeInt64(int64(len(ir.StringVal(n.X))))) {
base.Errorf("invalid string index %v (out of bounds for %d-byte string)", n.Index, len(ir.StringVal(n.X)))
} else if ir.ConstOverflow(x, types.Types[types.TINT]) {
base.Errorf("invalid %s index %v (index too large)", why, n.Index)
}
}
case types.TMAP:
n.Index = AssignConv(n.Index, t.Key(), "map index")
n.SetType(t.Elem())

View file

@ -152,7 +152,7 @@ func TestValuesInfo(t *testing.T) {
// look for expression
var expr syntax.Expr
for e := range info.Types {
if syntax.String(e) == test.expr {
if ExprString(e) == test.expr {
expr = e
break
}
@ -424,7 +424,7 @@ func TestTypesInfo(t *testing.T) {
// look for expression type
var typ Type
for e, tv := range info.Types {
if syntax.String(e) == test.expr {
if ExprString(e) == test.expr {
typ = tv.Type
break
}
@ -1135,8 +1135,8 @@ func TestPredicatesInfo(t *testing.T) {
// look for expression predicates
got := "<missing>"
for e, tv := range info.Types {
//println(name, syntax.String(e))
if syntax.String(e) == test.expr {
//println(name, ExprString(e))
if ExprString(e) == test.expr {
got = predString(tv)
break
}

View file

@ -24,7 +24,10 @@ func (check *Checker) assignment(x *operand, T Type, context string) {
switch x.mode {
case invalid:
return // error reported before
case constant_, variable, mapindex, value, nilvalue, commaok, commaerr:
case nilvalue:
assert(isTypes2)
// ok
case constant_, variable, mapindex, value, commaok, commaerr:
// ok
default:
// we may get here because of other problems (go.dev/issue/39634, crash 12)
@ -41,14 +44,25 @@ func (check *Checker) assignment(x *operand, T Type, context string) {
// bool, rune, int, float64, complex128 or string respectively, depending
// on whether the value is a boolean, rune, integer, floating-point,
// complex, or string constant."
if x.isNil() {
if T == nil {
check.errorf(x, UntypedNilUse, "use of untyped nil in %s", context)
x.mode = invalid
return
if isTypes2 {
if x.isNil() {
if T == nil {
check.errorf(x, UntypedNilUse, "use of untyped nil in %s", context)
x.mode = invalid
return
}
} else if T == nil || isNonTypeParamInterface(T) {
target = Default(x.typ)
}
} else { // go/types
if T == nil || isNonTypeParamInterface(T) {
if T == nil && x.typ == Typ[UntypedNil] {
check.errorf(x, UntypedNilUse, "use of untyped nil in %s", context)
x.mode = invalid
return
}
target = Default(x.typ)
}
} else if T == nil || isNonTypeParamInterface(T) {
target = Default(x.typ)
}
newType, val, code := check.implicitTypeAndValue(x, target)
if code != 0 {
@ -218,7 +232,7 @@ func (check *Checker) lhsVar(lhs syntax.Expr) Type {
var op operand
check.expr(nil, &op, sel.X)
if op.mode == mapindex {
check.errorf(&x, UnaddressableFieldAssign, "cannot assign to struct field %s in map", syntax.String(x.expr))
check.errorf(&x, UnaddressableFieldAssign, "cannot assign to struct field %s in map", ExprString(x.expr))
return Typ[Invalid]
}
}
@ -245,10 +259,10 @@ func (check *Checker) assignVar(lhs, rhs syntax.Expr, x *operand, context string
if x == nil {
var target *target
// avoid calling syntax.String if not needed
// avoid calling ExprString if not needed
if T != nil {
if _, ok := under(T).(*Signature); ok {
target = newTarget(T, syntax.String(lhs))
target = newTarget(T, ExprString(lhs))
}
}
x = new(operand)
@ -343,12 +357,11 @@ func (check *Checker) returnError(at poser, lhs []*Var, rhs []*operand) {
} else if r > 0 {
at = rhs[r-1] // report at last value
}
var err error_
err.code = WrongResultCount
err.errorf(at, "%s return values", qualifier)
err.errorf(nopos, "have %s", check.typesSummary(operandTypes(rhs), false))
err.errorf(nopos, "want %s", check.typesSummary(varTypes(lhs), false))
check.report(&err)
err := check.newError(WrongResultCount)
err.addf(at, "%s return values", qualifier)
err.addf(nopos, "have %s", check.typesSummary(operandTypes(rhs), false))
err.addf(nopos, "want %s", check.typesSummary(varTypes(lhs), false))
err.report()
}
// initVars type-checks assignments of initialization expressions orig_rhs
@ -493,7 +506,7 @@ func (check *Checker) assignVars(lhs, orig_rhs []syntax.Expr) {
// orig_rhs[0] was already evaluated
}
func (check *Checker) shortVarDecl(pos syntax.Pos, lhs, rhs []syntax.Expr) {
func (check *Checker) shortVarDecl(pos poser, lhs, rhs []syntax.Expr) {
top := len(check.delayed)
scope := check.scope
@ -506,6 +519,7 @@ func (check *Checker) shortVarDecl(pos syntax.Pos, lhs, rhs []syntax.Expr) {
ident, _ := lhs.(*syntax.Name)
if ident == nil {
check.useLHS(lhs)
// TODO(gri) This is redundant with a go/parser error. Consider omitting in go/types?
check.errorf(lhs, BadDecl, "non-name %s on left side of :=", lhs)
hasErr = true
continue
@ -568,7 +582,7 @@ func (check *Checker) shortVarDecl(pos syntax.Pos, lhs, rhs []syntax.Expr) {
// a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
// for short variable declarations) and ends at the end of the innermost
// containing block."
scopePos := syntax.EndPos(rhs[len(rhs)-1])
scopePos := endPos(rhs[len(rhs)-1])
for _, obj := range newVars {
check.declare(scope, nil, obj, scopePos) // id = nil: recordDef already called
}

View file

@ -23,8 +23,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
// append is the only built-in that permits the use of ... for the last argument
bin := predeclaredFuncs[id]
if hasDots(call) && id != _Append {
//check.errorf(call.Ellipsis, invalidOp + "invalid use of ... with built-in %s", bin.name)
check.errorf(call,
check.errorf(dddErrPos(call),
InvalidDotDotDot,
invalidOp+"invalid use of ... with built-in %s", bin.name)
check.use(argList...)
@ -76,7 +75,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
msg = "too many"
}
if msg != "" {
check.errorf(call, WrongArgCount, invalidOp+"%s arguments for %v (expected %d, found %d)", msg, call, bin.nargs, nargs)
check.errorf(argErrPos(call), WrongArgCount, invalidOp+"%s arguments for %v (expected %d, found %d)", msg, call, bin.nargs, nargs)
return
}
}
@ -909,7 +908,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
// trace is only available in test mode - no need to record signature
default:
unreachable()
panic("unreachable")
}
assert(x.mode != invalid)
@ -948,7 +947,7 @@ func hasVarSize(t Type, seen map[*Named]bool) (varSized bool) {
case *Interface:
return isTypeParam(t)
case *Named, *Union:
unreachable()
panic("unreachable")
}
return false
}
@ -991,7 +990,7 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x *operand, id builtinId)
case _Complex:
code = InvalidComplex
default:
unreachable()
panic("unreachable")
}
check.softErrorf(x, code, "%s not supported as argument to %s for go1.18 (see go.dev/issue/50937)", x, predeclaredFuncs[id].name)

View file

@ -207,7 +207,7 @@ func testBuiltinSignature(t *testing.T, name, src0, want string) {
// the recorded type for the built-in must match the wanted signature
typ := types[fun].Type
if typ == nil {
t.Errorf("%s: no type recorded for %s", src0, syntax.String(fun))
t.Errorf("%s: no type recorded for %s", src0, ExprString(fun))
return
}
if got := typ.String(); got != want {

View file

@ -108,12 +108,11 @@ func (check *Checker) funcInst(T *target, pos syntax.Pos, x *operand, inst *synt
// Note that NewTuple(params...) below is (*Tuple)(nil) if len(params) == 0, as desired.
tparams, params2 := check.renameTParams(pos, sig.TypeParams().list(), NewTuple(params...))
var err error_
targs = check.infer(pos, tparams, targs, params2.(*Tuple), args, reverse, &err)
err := check.newError(CannotInferTypeArgs)
targs = check.infer(pos, tparams, targs, params2.(*Tuple), args, reverse, err)
if targs == nil {
if !err.empty() {
err.code = CannotInferTypeArgs
check.report(&err)
err.report()
}
x.mode = invalid
return nil, nil
@ -528,12 +527,11 @@ func (check *Checker) arguments(call *syntax.CallExpr, sig *Signature, targs []T
if sig.params != nil {
params = sig.params.vars
}
var err error_
err.code = WrongArgCount
err.errorf(at, "%s arguments in call to %s", qualifier, call.Fun)
err.errorf(nopos, "have %s", check.typesSummary(operandTypes(args), false))
err.errorf(nopos, "want %s", check.typesSummary(varTypes(params), sig.variadic))
check.report(&err)
err := check.newError(WrongArgCount)
err.addf(at, "%s arguments in call to %s", qualifier, call.Fun)
err.addf(nopos, "have %s", check.typesSummary(operandTypes(args), false))
err.addf(nopos, "want %s", check.typesSummary(varTypes(params), sig.variadic))
err.report()
return
}
@ -606,15 +604,15 @@ func (check *Checker) arguments(call *syntax.CallExpr, sig *Signature, targs []T
// infer missing type arguments of callee and function arguments
if len(tparams) > 0 {
var err error_
targs = check.infer(call.Pos(), tparams, targs, sigParams, args, false, &err)
err := check.newError(CannotInferTypeArgs)
targs = check.infer(call.Pos(), tparams, targs, sigParams, args, false, err)
if targs == nil {
// TODO(gri) If infer inferred the first targs[:n], consider instantiating
// the call signature for better error messages/gopls behavior.
// Perhaps instantiate as much as we can, also for arguments.
// This will require changes to how infer returns its results.
if !err.empty() {
check.errorf(err.pos(), CannotInferTypeArgs, "in call to %s, %s", call.Fun, err.msg(check.qualifier))
check.errorf(err.pos(), CannotInferTypeArgs, "in call to %s, %s", call.Fun, err.msg())
}
return
}
@ -757,7 +755,7 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, def *TypeName
x.id = exp.id
default:
check.dump("%v: unexpected object %v", atPos(e.Sel), exp)
unreachable()
panic("unreachable")
}
x.expr = e
return
@ -910,7 +908,7 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, def *TypeName
check.addDeclDep(obj)
default:
unreachable()
panic("unreachable")
}
}

View file

@ -513,7 +513,7 @@ func (check *Checker) recordUntyped() {
for x, info := range check.untyped {
if debug && isTyped(info.typ) {
check.dump("%v: %s (type %s) is typed", atPos(x), x, info.typ)
unreachable()
panic("unreachable")
}
check.recordTypeAndValue(x, info.mode, info.typ, info.val)
}
@ -578,7 +578,7 @@ func (check *Checker) recordBuiltinType(f syntax.Expr, sig *Signature) {
case *syntax.ParenExpr:
f = p.X
default:
unreachable()
panic("unreachable")
}
}
}

View file

@ -118,7 +118,7 @@ func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *c
case Uint64:
return 0 <= x
default:
unreachable()
panic("unreachable")
}
}
// x does not fit into int64
@ -159,7 +159,7 @@ func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *c
case UntypedFloat:
return true
default:
unreachable()
panic("unreachable")
}
case isComplex(typ):
@ -191,7 +191,7 @@ func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *c
case UntypedComplex:
return true
default:
unreachable()
panic("unreachable")
}
case isString(typ):

View file

@ -98,17 +98,18 @@ func (check *Checker) conversion(x *operand, T Type) {
// given a type explicitly by a constant declaration or conversion,...".
if isUntyped(x.typ) {
final := T
// - For conversions to interfaces, except for untyped nil arguments,
// use the argument's default type.
// - For conversions to interfaces, except for untyped nil arguments
// and isTypes2, use the argument's default type.
// - For conversions of untyped constants to non-constant types, also
// use the default type (e.g., []byte("foo") should report string
// not []byte as type for the constant "foo").
// - If !isTypes2, keep untyped nil for untyped nil arguments.
// - For constant integer to string conversions, keep the argument type.
// (See also the TODO below.)
if x.typ == Typ[UntypedNil] {
if isTypes2 && x.typ == Typ[UntypedNil] {
// ok
} else if isNonTypeParamInterface(T) || constArg && !isConstType(T) {
final = Default(x.typ)
} else if isNonTypeParamInterface(T) || constArg && !isConstType(T) || !isTypes2 && x.isNil() {
final = Default(x.typ) // default type of untyped nil is untyped nil
} else if x.mode == constant_ && isInteger(x.typ) && allString(T) {
final = x.typ
}
@ -227,7 +228,7 @@ func (x *operand) convertibleTo(check *Checker, T Type, cause *string) bool {
return false
}
errorf := func(format string, args ...interface{}) {
errorf := func(format string, args ...any) {
if check != nil && cause != nil {
msg := check.sprintf(format, args...)
if *cause != "" {

View file

@ -16,7 +16,7 @@ func (err *error_) recordAltDecl(obj Object) {
// We use "other" rather than "previous" here because
// the first declaration seen may not be textually
// earlier in the source.
err.errorf(pos, "other declaration of %s", obj.Name())
err.addf(pos, "other declaration of %s", obj.Name())
}
}
@ -27,11 +27,10 @@ func (check *Checker) declare(scope *Scope, id *syntax.Name, obj Object, pos syn
// binding."
if obj.Name() != "_" {
if alt := scope.Insert(obj); alt != nil {
var err error_
err.code = DuplicateDecl
err.errorf(obj, "%s redeclared in this block", obj.Name())
err := check.newError(DuplicateDecl)
err.addf(obj, "%s redeclared in this block", obj.Name())
err.recordAltDecl(alt)
check.report(&err)
err.report()
return
}
obj.setScopePos(pos)
@ -162,7 +161,7 @@ func (check *Checker) objDecl(obj Object, def *TypeName) {
}
default:
unreachable()
panic("unreachable")
}
assert(obj.Type() != nil)
return
@ -171,7 +170,7 @@ func (check *Checker) objDecl(obj Object, def *TypeName) {
d := check.objMap[obj]
if d == nil {
check.dump("%v: %s should have been declared", obj.Pos(), obj)
unreachable()
panic("unreachable")
}
// save/restore current environment and set up object environment
@ -202,7 +201,7 @@ func (check *Checker) objDecl(obj Object, def *TypeName) {
// functions may be recursive - no need to track dependencies
check.funcDecl(obj, d)
default:
unreachable()
panic("unreachable")
}
}
@ -216,7 +215,7 @@ func (check *Checker) validCycle(obj Object) (valid bool) {
isPkgObj := obj.Parent() == check.pkg.scope
if isPkgObj != inObjMap {
check.dump("%v: inconsistent object map for %s (isPkgObj = %v, inObjMap = %v)", obj.Pos(), obj, isPkgObj, inObjMap)
unreachable()
panic("unreachable")
}
}
@ -266,7 +265,7 @@ loop:
case *Func:
// ignored for now
default:
unreachable()
panic("unreachable")
}
}
@ -343,15 +342,14 @@ func (check *Checker) cycleError(cycle []Object) {
return
}
var err error_
err.code = InvalidDeclCycle
err := check.newError(InvalidDeclCycle)
if tname != nil {
err.errorf(obj, "invalid recursive type %s", objName)
err.addf(obj, "invalid recursive type %s", objName)
} else {
err.errorf(obj, "invalid cycle in declaration of %s", objName)
err.addf(obj, "invalid cycle in declaration of %s", objName)
}
for range cycle {
err.errorf(obj, "%s refers to", objName)
err.addf(obj, "%s refers to", objName)
i++
if i >= len(cycle) {
i = 0
@ -359,8 +357,8 @@ func (check *Checker) cycleError(cycle []Object) {
obj = cycle[i]
objName = name(obj)
}
err.errorf(obj, "%s", objName)
check.report(&err)
err.addf(obj, "%s", objName)
err.report()
}
// firstInSrc reports the index of the object with the "smallest"
@ -433,7 +431,7 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init syntax.Expr) {
// if any, would not be checked.
//
// TODO(gri) If we have no init expr, we should distribute
// a given type otherwise we need to re-evalate the type
// a given type otherwise we need to re-evaluate the type
// expr for each lhs variable, leading to duplicate work.
}
@ -721,11 +719,10 @@ func (check *Checker) checkFieldUniqueness(base *Named) {
// For historical consistency, we report the primary error on the
// method, and the alt decl on the field.
var err error_
err.code = DuplicateFieldAndMethod
err.errorf(alt, "field and method with the same name %s", fld.name)
err := check.newError(DuplicateFieldAndMethod)
err.addf(alt, "field and method with the same name %s", fld.name)
err.recordAltDecl(fld)
check.report(&err)
err.report()
}
}
}

View file

@ -28,16 +28,22 @@ func assert(p bool) {
}
}
func unreachable() {
panic("unreachable")
// An error_ represents a type-checking error.
// A new error_ is created with Checker.newError.
// To report an error_, call error_.report.
type error_ struct {
check *Checker
desc []errorDesc
code Code
soft bool // TODO(gri) eventually determine this from an error code
}
// An error_ represents a type-checking error.
// To report an error_, call Checker.report.
type error_ struct {
desc []errorDesc
code Code
soft bool // TODO(gri) eventually determine this from an error code
// newError returns a new error_ with the given error code.
func (check *Checker) newError(code Code) *error_ {
if code == 0 {
panic("error code must not be 0")
}
return &error_{check: check, code: code}
}
// An errorDesc describes part of a type-checking error.
@ -58,10 +64,12 @@ func (err *error_) pos() syntax.Pos {
return err.desc[0].pos
}
func (err *error_) msg(qf Qualifier) string {
// msg returns the formatted error message without the primary error position pos().
func (err *error_) msg() string {
if err.empty() {
return "no error"
}
var buf strings.Builder
for i := range err.desc {
p := &err.desc[i]
@ -71,22 +79,18 @@ func (err *error_) msg(qf Qualifier) string {
fmt.Fprintf(&buf, "%s: ", p.pos)
}
}
buf.WriteString(sprintf(qf, false, p.format, p.args...))
buf.WriteString(err.check.sprintf(p.format, p.args...))
}
return buf.String()
}
// String is for testing.
func (err *error_) String() string {
if err.empty() {
return "no error"
}
return fmt.Sprintf("%s: %s", err.pos(), err.msg(nil))
}
// errorf adds formatted error information to err.
// addf adds formatted error information to err.
// It may be called multiple times to provide additional information.
func (err *error_) errorf(at poser, format string, args ...interface{}) {
// The position of the first call to addf determines the position of the reported Error.
// Subsequent calls to addf provide additional information in the form of additional lines
// in the error message (types2) or continuation errors identified by a tab-indented error
// message (go/types).
func (err *error_) addf(at poser, format string, args ...interface{}) {
err.desc = append(err.desc, errorDesc{atPos(at), format, args})
}
@ -102,7 +106,7 @@ func sprintf(qf Qualifier, tpSubscripts bool, format string, args ...interface{}
case syntax.Pos:
arg = a.String()
case syntax.Expr:
arg = syntax.String(a)
arg = ExprString(a)
case []syntax.Expr:
var buf strings.Builder
buf.WriteByte('[')
@ -110,7 +114,7 @@ func sprintf(qf Qualifier, tpSubscripts bool, format string, args ...interface{}
if i > 0 {
buf.WriteString(", ")
}
buf.WriteString(syntax.String(x))
buf.WriteString(ExprString(x))
}
buf.WriteByte(']')
arg = buf.String()
@ -200,13 +204,6 @@ func (check *Checker) sprintf(format string, args ...interface{}) string {
return sprintf(qf, false, format, args...)
}
func (check *Checker) report(err *error_) {
if err.empty() {
panic("no error to report")
}
check.err(err.pos(), err.code, err.msg(check.qualifier), err.soft)
}
func (check *Checker) trace(pos syntax.Pos, format string, args ...interface{}) {
fmt.Printf("%s:\t%s%s\n",
pos,
@ -220,38 +217,48 @@ func (check *Checker) dump(format string, args ...interface{}) {
fmt.Println(sprintf(check.qualifier, true, format, args...))
}
func (check *Checker) err(at poser, code Code, msg string, soft bool) {
switch code {
case InvalidSyntaxTree:
// report reports the error err, setting check.firstError if necessary.
func (err *error_) report() {
if err.empty() {
panic("no error to report")
}
msg := err.msg()
code := err.code
assert(code != 0)
if code == InvalidSyntaxTree {
msg = "invalid syntax tree: " + msg
case 0:
panic("no error code provided")
}
// Cheap trick: Don't report errors with messages containing
// "invalid operand" or "invalid type" as those tend to be
// follow-on errors which don't add useful information. Only
// exclude them if these strings are not at the beginning,
// and only if we have at least one error already reported.
if check.firstErr != nil && (strings.Index(msg, "invalid operand") > 0 || strings.Index(msg, "invalid type") > 0) {
return
}
pos := atPos(at)
// If we are encountering an error while evaluating an inherited
// constant initialization expression, pos is the position of in
// the original expression, and not of the currently declared
// constant identifier. Use the provided errpos instead.
// TODO(gri) We may also want to augment the error message and
// refer to the position (pos) in the original expression.
check := err.check
pos := err.pos()
if check.errpos.IsKnown() {
assert(check.iota != nil)
pos = check.errpos
}
if check.conf.Trace {
check.trace(pos, "ERROR: %s", msg)
}
// Cheap trick: Don't report errors with messages containing
// "invalid operand" or "invalid type" as those tend to be
// follow-on errors which don't add useful information. Only
// exclude them if these strings are not at the beginning,
// and only if we have at least one error already reported.
isInvalidErr := strings.Index(msg, "invalid operand") > 0 || strings.Index(msg, "invalid type") > 0
if check.firstErr != nil && isInvalidErr {
return
}
// If we have a URL for error codes, add a link to the first line.
if code != 0 && check.conf.ErrorURL != "" {
if check.conf.ErrorURL != "" {
u := fmt.Sprintf(check.conf.ErrorURL, code)
if i := strings.Index(msg, "\n"); i >= 0 {
msg = msg[:i] + u + msg[i:]
@ -260,20 +267,27 @@ func (check *Checker) err(at poser, code Code, msg string, soft bool) {
}
}
err := Error{pos, stripAnnotations(msg), msg, soft, code}
if check.firstErr == nil {
check.firstErr = err
e := Error{
Pos: pos,
Msg: stripAnnotations(msg),
Full: msg,
Soft: err.soft,
Code: code,
}
if check.conf.Trace {
check.trace(pos, "ERROR: %s", msg)
if check.firstErr == nil {
check.firstErr = e
}
f := check.conf.Error
if f == nil {
panic(bailout{}) // report only first error
}
f(err)
// TODO(gri) If e contains \t-indented sub-errors,
// for go/types f must be called for each
// of those sub-errors.
f(e)
}
const (
@ -286,21 +300,29 @@ type poser interface {
}
func (check *Checker) error(at poser, code Code, msg string) {
check.err(at, code, msg, false)
err := check.newError(code)
err.addf(at, "%s", msg)
err.report()
}
func (check *Checker) errorf(at poser, code Code, format string, args ...interface{}) {
check.err(at, code, check.sprintf(format, args...), false)
err := check.newError(code)
err.addf(at, format, args...)
err.report()
}
func (check *Checker) softErrorf(at poser, code Code, format string, args ...interface{}) {
check.err(at, code, check.sprintf(format, args...), true)
err := check.newError(code)
err.addf(at, format, args...)
err.soft = true
err.report()
}
func (check *Checker) versionErrorf(at poser, v goVersion, format string, args ...interface{}) {
msg := check.sprintf(format, args...)
msg = fmt.Sprintf("%s requires %s or later", msg, v)
check.err(at, UnsupportedFeature, msg, true)
err := check.newError(UnsupportedFeature)
err.addf(at, "%s requires %s or later", msg, v)
err.report()
}
// atPos reports the left (= start) position of at.

View file

@ -9,19 +9,19 @@ import "testing"
func TestError(t *testing.T) {
var err error_
want := "no error"
if got := err.String(); got != want {
if got := err.msg(); got != want {
t.Errorf("empty error: got %q, want %q", got, want)
}
want = "<unknown position>: foo 42"
err.errorf(nopos, "foo %d", 42)
if got := err.String(); got != want {
want = "foo 42"
err.addf(nopos, "foo %d", 42)
if got := err.msg(); got != want {
t.Errorf("simple error: got %q, want %q", got, want)
}
want = "<unknown position>: foo 42\n\tbar 43"
err.errorf(nopos, "bar %d", 43)
if got := err.String(); got != want {
want = "foo 42\n\tbar 43"
err.addf(nopos, "bar %d", 43)
if got := err.msg(); got != want {
t.Errorf("simple error: got %q, want %q", got, want)
}
}

View file

@ -268,7 +268,7 @@ func (check *Checker) updateExprType0(parent, x syntax.Expr, typ Type, final boo
// upon assignment or use.
if debug {
check.dump("%v: found old type(%s): %s (new: %s)", atPos(x), x, old.typ, typ)
unreachable()
panic("unreachable")
}
return
@ -337,7 +337,7 @@ func (check *Checker) updateExprType0(parent, x syntax.Expr, typ Type, final boo
}
default:
unreachable()
panic("unreachable")
}
// If the new type is not final and still untyped, just
@ -546,7 +546,7 @@ func (check *Checker) comparison(x, y *operand, op syntax.Operator, switchCase b
}
default:
unreachable()
panic("unreachable")
}
// comparison is ok
@ -1042,7 +1042,7 @@ func (check *Checker) exprInternal(T *target, x *operand, e syntax.Expr, hint Ty
switch e := e.(type) {
case nil:
unreachable()
panic("unreachable")
case *syntax.BadExpr:
goto Error // error was reported before
@ -1654,7 +1654,7 @@ func (check *Checker) exclude(x *operand, modeset uint) {
msg = "%s is not an expression"
code = NotAnExpr
default:
unreachable()
panic("unreachable")
}
check.errorf(x, code, msg, x)
x.mode = invalid

View file

@ -56,7 +56,7 @@ func (s *gcSizes) Alignof(T Type) (result int64) {
return s.WordSize
}
case *TypeParam, *Union:
unreachable()
panic("unreachable")
}
a := s.Sizeof(T) // may be 0 or negative
// spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
@ -154,7 +154,7 @@ func (s *gcSizes) Sizeof(T Type) int64 {
assert(!isTypeParam(T))
return s.WordSize * 2
case *TypeParam, *Union:
unreachable()
panic("unreachable")
}
return s.WordSize // catch-all
}

View file

@ -127,7 +127,7 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
}
}
if allFailed {
err.errorf(arg, "type %s of %s does not match %s (cannot infer %s)", targ, arg.expr, tpar, typeParamsString(tparams))
err.addf(arg, "type %s of %s does not match %s (cannot infer %s)", targ, arg.expr, tpar, typeParamsString(tparams))
return
}
}
@ -140,12 +140,12 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
// the more general CannotInferTypeArgs.
if inferred != tpar {
if reverse {
err.errorf(arg, "inferred type %s for %s does not match type %s of %s", inferred, tpar, targ, arg.expr)
err.addf(arg, "inferred type %s for %s does not match type %s of %s", inferred, tpar, targ, arg.expr)
} else {
err.errorf(arg, "type %s of %s does not match inferred type %s for %s", targ, arg.expr, inferred, tpar)
err.addf(arg, "type %s of %s does not match inferred type %s for %s", targ, arg.expr, inferred, tpar)
}
} else {
err.errorf(arg, "type %s of %s does not match %s", targ, arg.expr, tpar)
err.addf(arg, "type %s of %s does not match %s", targ, arg.expr, tpar)
}
}
@ -252,7 +252,7 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
// TODO(gri) Type parameters that appear in the constraint and
// for which we have type arguments inferred should
// use those type arguments for a better error message.
err.errorf(pos, "%s (type %s) does not satisfy %s", tpar, tx, tpar.Constraint())
err.addf(pos, "%s (type %s) does not satisfy %s", tpar, tx, tpar.Constraint())
return nil
}
case single && !core.tilde:
@ -277,7 +277,7 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
constraint := tpar.iface()
if m, _ := check.missingMethod(tx, constraint, true, func(x, y Type) bool { return u.unify(x, y, exact) }, &cause); m != nil {
// TODO(gri) better error message (see TODO above)
err.errorf(pos, "%s (type %s) does not satisfy %s %s", tpar, tx, tpar.Constraint(), cause)
err.addf(pos, "%s (type %s) does not satisfy %s %s", tpar, tx, tpar.Constraint(), cause)
return nil
}
}
@ -318,7 +318,7 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
} else {
m := maxType(max, arg.typ)
if m == nil {
err.errorf(arg, "mismatched types %s and %s (cannot infer %s)", max, arg.typ, tpar)
err.addf(arg, "mismatched types %s and %s (cannot infer %s)", max, arg.typ, tpar)
return nil
}
max = m
@ -427,7 +427,7 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
for i, typ := range inferred {
if typ == nil || isParameterized(tparams, typ) {
obj := tparams[i].obj
err.errorf(pos, "cannot infer %s (%s)", obj.name, obj.pos)
err.addf(pos, "cannot infer %s (%s)", obj.name, obj.pos)
return nil
}
}

View file

@ -160,17 +160,16 @@ func (check *Checker) reportCycle(cycle []Object) {
return
}
var err error_
err.code = InvalidInitCycle
err.errorf(obj, "initialization cycle for %s", obj.Name())
err := check.newError(InvalidInitCycle)
err.addf(obj, "initialization cycle for %s", obj.Name())
// subtle loop: print cycle[i] for i = 0, n-1, n-2, ... 1 for len(cycle) = n
for i := len(cycle) - 1; i >= 0; i-- {
err.errorf(obj, "%s refers to", obj.Name())
err.addf(obj, "%s refers to", obj.Name())
obj = cycle[i]
}
// print cycle[0] again to close the cycle
err.errorf(obj, "%s", obj.Name())
check.report(&err)
err.addf(obj, "%s", obj.Name())
err.report()
}
// ----------------------------------------------------------------------------

View file

@ -698,14 +698,14 @@ func TestIssue51093(t *testing.T) {
n++
tpar, _ := tv.Type.(*TypeParam)
if tpar == nil {
t.Fatalf("%s: got type %s, want type parameter", syntax.String(x), tv.Type)
t.Fatalf("%s: got type %s, want type parameter", ExprString(x), tv.Type)
}
if name := tpar.Obj().Name(); name != "P" {
t.Fatalf("%s: got type parameter name %s, want P", syntax.String(x), name)
t.Fatalf("%s: got type parameter name %s, want P", ExprString(x), name)
}
// P(val) must not be constant
if tv.Value != nil {
t.Errorf("%s: got constant value %s (%s), want no constant", syntax.String(x), tv.Value, tv.Value.String())
t.Errorf("%s: got constant value %s (%s), want no constant", ExprString(x), tv.Value, tv.Value.String())
}
}
}

View file

@ -133,12 +133,11 @@ func (check *Checker) blockBranches(all *Scope, parent *block, lstmt *syntax.Lab
if name := s.Label.Value; name != "_" {
lbl := NewLabel(s.Label.Pos(), check.pkg, name)
if alt := all.Insert(lbl); alt != nil {
var err error_
err.code = DuplicateLabel
err := check.newError(DuplicateLabel)
err.soft = true
err.errorf(lbl.pos, "label %s already declared", name)
err.addf(lbl.pos, "label %s already declared", name)
err.recordAltDecl(alt)
check.report(&err)
err.report()
// ok to continue
} else {
b.insert(s)

View file

@ -472,7 +472,7 @@ func (check *Checker) missingMethod(V, T Type, static bool, equivalent func(x, y
case field:
*cause = check.sprintf("(%s.%s is a field, not a method)", V, m.Name())
default:
unreachable()
panic("unreachable")
}
}

View file

@ -137,10 +137,9 @@ func (check *Checker) reportInstanceLoop(v int) {
// TODO(mdempsky): Pivot stack so we report the cycle from the top?
var err error_
err.code = InvalidInstanceCycle
err := check.newError(InvalidInstanceCycle)
obj0 := check.mono.vertices[v].obj
err.errorf(obj0, "instantiation cycle:")
err.addf(obj0, "instantiation cycle:")
qf := RelativeTo(check.pkg)
for _, v := range stack {
@ -151,12 +150,12 @@ func (check *Checker) reportInstanceLoop(v int) {
default:
panic("unexpected type")
case *Named:
err.errorf(edge.pos, "%s implicitly parameterized by %s", obj.Name(), TypeString(edge.typ, qf)) // secondary error, \t indented
err.addf(edge.pos, "%s implicitly parameterized by %s", obj.Name(), TypeString(edge.typ, qf)) // secondary error, \t indented
case *TypeParam:
err.errorf(edge.pos, "%s instantiated as %s", obj.Name(), TypeString(edge.typ, qf)) // secondary error, \t indented
err.addf(edge.pos, "%s instantiated as %s", obj.Name(), TypeString(edge.typ, qf)) // secondary error, \t indented
}
}
check.report(&err)
err.report()
}
// recordCanon records that tpar is the canonical type parameter

View file

@ -11,7 +11,6 @@ import (
"cmd/compile/internal/syntax"
"fmt"
"go/constant"
"go/token"
. "internal/types/errors"
)
@ -27,7 +26,7 @@ const (
variable // operand is an addressable variable
mapindex // operand is a map index expression (acts like a variable on lhs, commaok on rhs of an assignment)
value // operand is a computed value
nilvalue // operand is the nil value
nilvalue // operand is the nil value - only used by types2
commaok // like value, but operand may be used in a comma,ok expression
commaerr // like commaok, but second value is error, not boolean
cgofunc // operand is a cgo function
@ -42,7 +41,7 @@ var operandModeString = [...]string{
variable: "variable",
mapindex: "map index expression",
value: "value",
nilvalue: "nil",
nilvalue: "nil", // only used by types2
commaok: "comma, ok expression",
commaerr: "comma, error expression",
cgofunc: "cgo function",
@ -109,14 +108,20 @@ func (x *operand) Pos() syntax.Pos {
// cgofunc <expr> ( <mode> of type <typ>)
func operandString(x *operand, qf Qualifier) string {
// special-case nil
if x.mode == nilvalue {
switch x.typ {
case nil, Typ[Invalid]:
return "nil (with invalid type)"
case Typ[UntypedNil]:
if isTypes2 {
if x.mode == nilvalue {
switch x.typ {
case nil, Typ[Invalid]:
return "nil (with invalid type)"
case Typ[UntypedNil]:
return "nil"
default:
return fmt.Sprintf("nil (of type %s)", TypeString(x.typ, qf))
}
}
} else { // go/types
if x.mode == value && x.typ == Typ[UntypedNil] {
return "nil"
default:
return fmt.Sprintf("nil (of type %s)", TypeString(x.typ, qf))
}
}
@ -124,7 +129,7 @@ func operandString(x *operand, qf Qualifier) string {
var expr string
if x.expr != nil {
expr = syntax.String(x.expr)
expr = ExprString(x.expr)
} else {
switch x.mode {
case builtin:
@ -221,10 +226,10 @@ func (x *operand) setConst(k syntax.LitKind, lit string) {
case syntax.StringLit:
kind = UntypedString
default:
unreachable()
panic("unreachable")
}
val := constant.MakeFromLiteral(lit, kind2tok[k], 0)
val := makeFromLiteral(lit, k)
if val.Kind() == constant.Unknown {
x.mode = invalid
x.typ = Typ[Invalid]
@ -236,7 +241,13 @@ func (x *operand) setConst(k syntax.LitKind, lit string) {
}
// isNil reports whether x is the (untyped) nil value.
func (x *operand) isNil() bool { return x.mode == nilvalue }
func (x *operand) isNil() bool {
if isTypes2 {
return x.mode == nilvalue
} else { // go/types
return x.mode == value && x.typ == Typ[UntypedNil]
}
}
// assignableTo reports whether x is assignable to a variable of type T. If the
// result is false and a non-nil cause is provided, it may be set to a more
@ -332,7 +343,7 @@ func (x *operand) assignableTo(check *Checker, T Type, cause *string) (bool, Cod
return false, IncompatibleAssign
}
errorf := func(format string, args ...interface{}) {
errorf := func(format string, args ...any) {
if check != nil && cause != nil {
msg := check.sprintf(format, args...)
if *cause != "" {
@ -385,12 +396,3 @@ func (x *operand) assignableTo(check *Checker, T Type, cause *string) (bool, Cod
return false, IncompatibleAssign
}
// kind2tok translates syntax.LitKinds into token.Tokens.
var kind2tok = [...]token.Token{
syntax.IntLit: token.INT,
syntax.FloatLit: token.FLOAT,
syntax.ImagLit: token.IMAG,
syntax.RuneLit: token.CHAR,
syntax.StringLit: token.STRING,
}

View file

@ -477,7 +477,7 @@ func (c *comparer) identical(x, y Type, p *ifacePair) bool {
// avoid a crash in case of nil type
default:
unreachable()
panic("unreachable")
}
return false

View file

@ -314,11 +314,10 @@ func (check *Checker) collectObjects() {
// the object may be imported into more than one file scope
// concurrently. See go.dev/issue/32154.)
if alt := fileScope.Lookup(name); alt != nil {
var err error_
err.code = DuplicateDecl
err.errorf(s.LocalPkgName, "%s redeclared in this block", alt.Name())
err := check.newError(DuplicateDecl)
err.addf(s.LocalPkgName, "%s redeclared in this block", alt.Name())
err.recordAltDecl(alt)
check.report(&err)
err.report()
} else {
fileScope.insert(name, obj)
check.dotImportMap[dotImportKey{fileScope, name}] = pkgName
@ -473,17 +472,16 @@ func (check *Checker) collectObjects() {
for name, obj := range scope.elems {
if alt := pkg.scope.Lookup(name); alt != nil {
obj = resolve(name, obj)
var err error_
err.code = DuplicateDecl
err := check.newError(DuplicateDecl)
if pkg, ok := obj.(*PkgName); ok {
err.errorf(alt, "%s already declared through import of %s", alt.Name(), pkg.Imported())
err.addf(alt, "%s already declared through import of %s", alt.Name(), pkg.Imported())
err.recordAltDecl(pkg)
} else {
err.errorf(alt, "%s already declared through dot-import of %s", alt.Name(), obj.Pkg())
err.addf(alt, "%s already declared through dot-import of %s", alt.Name(), obj.Pkg())
// TODO(gri) dot-imported objects don't have a position; recordAltDecl won't print anything
err.recordAltDecl(obj)
}
check.report(&err)
err.report()
}
}
}

View file

@ -16,7 +16,7 @@ import (
func (check *Checker) isTerminating(s syntax.Stmt, label string) bool {
switch s := s.(type) {
default:
unreachable()
panic("unreachable")
case *syntax.DeclStmt, *syntax.EmptyStmt, *syntax.SendStmt,
*syntax.AssignStmt, *syntax.CallStmt:
@ -108,7 +108,7 @@ func (check *Checker) isTerminatingSwitch(body []*syntax.CaseClause, label strin
func hasBreak(s syntax.Stmt, label string, implicit bool) bool {
switch s := s.(type) {
default:
unreachable()
panic("unreachable")
case *syntax.DeclStmt, *syntax.EmptyStmt, *syntax.ExprStmt,
*syntax.SendStmt, *syntax.AssignStmt, *syntax.CallStmt,

View file

@ -163,7 +163,7 @@ func SelectionString(s *Selection, qf Qualifier) string {
case MethodExpr:
k = "method expr "
default:
unreachable()
panic("unreachable")
}
var buf bytes.Buffer
buf.WriteString(k)

View file

@ -186,11 +186,10 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
params, variadic := check.collectParams(scope, ftyp.ParamList, true, scopePos)
results, _ := check.collectParams(scope, ftyp.ResultList, false, scopePos)
scope.Squash(func(obj, alt Object) {
var err error_
err.code = DuplicateDecl
err.errorf(obj, "%s redeclared in this block", obj.Name())
err := check.newError(DuplicateDecl)
err.addf(obj, "%s redeclared in this block", obj.Name())
err.recordAltDecl(alt)
check.report(&err)
err.report()
})
if recvPar != nil {
@ -247,7 +246,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
case *TypeParam:
// The underlying type of a receiver base type cannot be a
// type parameter: "type T[P any] P" is not a valid declaration.
unreachable()
panic("unreachable")
}
if cause != "" {
check.errorf(recv, InvalidRecv, "invalid receiver type %s (%s)", rtyp, cause)

View file

@ -94,7 +94,7 @@ func (s *StdSizes) Alignof(T Type) (result int64) {
return s.WordSize
}
case *TypeParam, *Union:
unreachable()
panic("unreachable")
}
a := s.Sizeof(T) // may be 0 or negative
// spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
@ -221,7 +221,7 @@ func (s *StdSizes) Sizeof(T Type) int64 {
assert(!isTypeParam(T))
return s.WordSize * 2
case *TypeParam, *Union:
unreachable()
panic("unreachable")
}
return s.WordSize // catch-all
}

View file

@ -186,7 +186,7 @@ func (check *Checker) suspendedCall(keyword string, call syntax.Expr) {
case statement:
return
default:
unreachable()
panic("unreachable")
}
check.errorf(&x, code, "%s %s %s", keyword, msg, &x)
}
@ -260,11 +260,10 @@ L:
// (quadratic algorithm, but these lists tend to be very short)
for _, vt := range seen[val] {
if Identical(v.typ, vt.typ) {
var err error_
err.code = DuplicateCase
err.errorf(&v, "duplicate case %s in expression switch", &v)
err.errorf(vt.pos, "previous case")
check.report(&err)
err := check.newError(DuplicateCase)
err.addf(&v, "duplicate case %s in expression switch", &v)
err.addf(vt.pos, "previous case")
err.report()
continue L
}
}
@ -307,11 +306,10 @@ L:
if T != nil {
Ts = TypeString(T, check.qualifier)
}
var err error_
err.code = DuplicateCase
err.errorf(e, "duplicate case %s in type switch", Ts)
err.errorf(other, "previous case")
check.report(&err)
err := check.newError(DuplicateCase)
err.addf(e, "duplicate case %s in type switch", Ts)
err.addf(other, "previous case")
err.report()
continue L
}
}
@ -350,11 +348,10 @@ L:
// if T != nil {
// Ts = TypeString(T, check.qualifier)
// }
// var err error_
// err.code = _DuplicateCase
// err.errorf(e, "duplicate case %s in type switch", Ts)
// err.errorf(other, "previous case")
// check.report(&err)
// err := check.newError(_DuplicateCase)
// err.addf(e, "duplicate case %s in type switch", Ts)
// err.addf(other, "previous case")
// err.report()
// continue L
// }
// seen[hash] = e
@ -498,11 +495,10 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) {
// with the same name as a result parameter is in scope at the place of the return."
for _, obj := range res.vars {
if alt := check.lookup(obj.name); alt != nil && alt != obj {
var err error_
err.code = OutOfScopeResult
err.errorf(s, "result parameter %s not in scope at return", obj.name)
err.errorf(alt, "inner declaration of %s", obj)
check.report(&err)
err := check.newError(OutOfScopeResult)
err.addf(s, "result parameter %s not in scope at return", obj.name)
err.addf(alt, "inner declaration of %s", obj)
err.report()
// ok to continue
}
}

View file

@ -200,11 +200,10 @@ func embeddedFieldIdent(e syntax.Expr) *syntax.Name {
func (check *Checker) declareInSet(oset *objset, pos syntax.Pos, obj Object) bool {
if alt := oset.insert(obj); alt != nil {
var err error_
err.code = DuplicateDecl
err.errorf(pos, "%s redeclared", obj.Name())
err := check.newError(DuplicateDecl)
err.addf(pos, "%s redeclared", obj.Name())
err.recordAltDecl(alt)
check.report(&err)
err.report()
return false
}
return true

View file

@ -95,6 +95,18 @@ func (subst *subster) typ(typ Type) Type {
case *Basic:
// nothing to do
case *Alias:
rhs := subst.typ(t.fromRHS)
if rhs != t.fromRHS {
// This branch cannot be reached because the RHS of an alias
// may only contain type parameters of an enclosing function.
// Such function bodies are never "instantiated" and thus
// substitution is not called on locally declared alias types.
// TODO(gri) adjust once parameterized aliases are supported
panic("unreachable for unparameterized aliases")
// return subst.check.newAlias(t.obj, rhs)
}
case *Array:
elem := subst.typOrNil(t.elem)
if elem != t.elem {
@ -271,7 +283,7 @@ func (subst *subster) typ(typ Type) Type {
return subst.smap.lookup(t)
default:
unreachable()
panic("unreachable")
}
return typ

View file

@ -221,11 +221,10 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_
mpos[m] = pos
case explicit:
if check != nil {
var err error_
err.code = DuplicateDecl
err.errorf(pos, "duplicate method %s", m.name)
err.errorf(mpos[other.(*Func)], "other declaration of %s", m.name)
check.report(&err)
err := check.newError(DuplicateDecl)
err.addf(pos, "duplicate method %s", m.name)
err.addf(mpos[other.(*Func)], "other declaration of %s", m.name)
err.report()
}
default:
// We have a duplicate method name in an embedded (not explicitly declared) method.
@ -236,11 +235,10 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_
if check != nil {
check.later(func() {
if !check.allowVersion(m.pkg, pos, go1_14) || !Identical(m.typ, other.Type()) {
var err error_
err.code = DuplicateDecl
err.errorf(pos, "duplicate method %s", m.name)
err.errorf(mpos[other.(*Func)], "other declaration of %s", m.name)
check.report(&err)
err := check.newError(DuplicateDecl)
err.addf(pos, "duplicate method %s", m.name)
err.addf(mpos[other.(*Func)], "other declaration of %s", m.name)
err.report()
}
}).describef(pos, "duplicate method check for %s", m.name)
}

View file

@ -16,18 +16,18 @@ import (
)
// A Qualifier controls how named package-level objects are printed in
// calls to TypeString, ObjectString, and SelectionString.
// calls to [TypeString], [ObjectString], and [SelectionString].
//
// These three formatting routines call the Qualifier for each
// package-level object O, and if the Qualifier returns a non-empty
// string p, the object is printed in the form p.O.
// If it returns an empty string, only the object name O is printed.
//
// Using a nil Qualifier is equivalent to using (*Package).Path: the
// Using a nil Qualifier is equivalent to using (*[Package]).Path: the
// object is qualified by the import path, e.g., "encoding/json.Marshal".
type Qualifier func(*Package) string
// RelativeTo returns a Qualifier that fully qualifies members of
// RelativeTo returns a [Qualifier] that fully qualifies members of
// all packages other than pkg.
func RelativeTo(pkg *Package) Qualifier {
if pkg == nil {
@ -42,7 +42,7 @@ func RelativeTo(pkg *Package) Qualifier {
}
// TypeString returns the string representation of typ.
// The Qualifier controls the printing of
// The [Qualifier] controls the printing of
// package-level objects, and may be nil.
func TypeString(typ Type, qf Qualifier) string {
var buf bytes.Buffer
@ -51,14 +51,14 @@ func TypeString(typ Type, qf Qualifier) string {
}
// WriteType writes the string representation of typ to buf.
// The Qualifier controls the printing of
// The [Qualifier] controls the printing of
// package-level objects, and may be nil.
func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
newTypeWriter(buf, qf).typ(typ)
}
// WriteSignature writes the representation of the signature sig to buf,
// without a leading "func" keyword. The Qualifier controls the printing
// without a leading "func" keyword. The [Qualifier] controls the printing
// of package-level objects, and may be nil.
func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
newTypeWriter(buf, qf).signature(sig)
@ -322,7 +322,13 @@ func (w *typeWriter) typ(typ Type) {
// error messages. This doesn't need to be super-elegant; we just
// need a clear indication that this is not a predeclared name.
if w.ctxt == nil && Universe.Lookup(t.obj.name) != nil {
w.string(fmt.Sprintf(" /* with %s declared at %s */", t.obj.name, t.obj.Pos()))
if isTypes2 {
w.string(fmt.Sprintf(" /* with %s declared at %v */", t.obj.name, t.obj.Pos()))
} else {
// Can't print position information because
// we don't have a token.FileSet accessible.
w.string("/* type parameter */")
}
}
}

View file

@ -139,7 +139,7 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *TypeName, wantType
x.mode = nilvalue
default:
unreachable()
panic("unreachable")
}
x.typ = typ

View file

@ -279,7 +279,7 @@ func def(obj Object) {
case *Builtin:
obj.pkg = Unsafe
default:
unreachable()
panic("unreachable")
}
}
if scope.Insert(obj) != nil {

View file

@ -9,7 +9,13 @@
package types2
import "cmd/compile/internal/syntax"
import (
"cmd/compile/internal/syntax"
"go/constant"
"go/token"
)
const isTypes2 = true
// cmpPos compares the positions p and q and returns a result r as follows:
//
@ -23,3 +29,31 @@ func cmpPos(p, q syntax.Pos) int { return p.Cmp(q) }
// hasDots reports whether the last argument in the call is followed by ...
func hasDots(call *syntax.CallExpr) bool { return call.HasDots }
// dddErrPos returns the node (poser) for reporting an invalid ... use in a call.
func dddErrPos(call *syntax.CallExpr) *syntax.CallExpr {
// TODO(gri) should use "..." instead of call position
return call
}
// argErrPos returns the node (poser) for reportign an invalid argument count.
func argErrPos(call *syntax.CallExpr) *syntax.CallExpr { return call }
// ExprString returns a string representation of x.
func ExprString(x syntax.Node) string { return syntax.String(x) }
// endPos returns the position of the first character immediately after node n.
func endPos(n syntax.Node) syntax.Pos { return syntax.EndPos(n) }
// makeFromLiteral returns the constant value for the given literal string and kind.
func makeFromLiteral(lit string, kind syntax.LitKind) constant.Value {
return constant.MakeFromLiteral(lit, kind2tok[kind], 0)
}
var kind2tok = [...]token.Token{
syntax.IntLit: token.INT,
syntax.FloatLit: token.FLOAT,
syntax.ImagLit: token.IMAG,
syntax.RuneLit: token.CHAR,
syntax.StringLit: token.STRING,
}

View file

@ -6,6 +6,7 @@ package walk
import (
"fmt"
"internal/abi"
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
@ -183,8 +184,7 @@ var mapassign = mkmapnames("mapassign", "ptr")
var mapdelete = mkmapnames("mapdelete", "")
func mapfast(t *types.Type) int {
// Check runtime/map.go:maxElemSize before changing.
if t.Elem().Size() > 128 {
if t.Elem().Size() > abi.MapMaxElemBytes {
return mapslow
}
switch reflectdata.AlgType(t.Key()) {

19
src/cmd/dist/build.go vendored
View file

@ -40,7 +40,6 @@ var (
goppc64 string
goriscv64 string
goroot string
goroot_final string
goextlinkenabled string
gogcflags string // For running built compiler
goldflags string
@ -127,12 +126,6 @@ func xinit() {
// All exec calls rewrite "go" into gorootBinGo.
gorootBinGo = pathf("%s/bin/go", goroot)
b = os.Getenv("GOROOT_FINAL")
if b == "" {
b = goroot
}
goroot_final = b
b = os.Getenv("GOOS")
if b == "" {
b = gohostos
@ -245,7 +238,6 @@ func xinit() {
os.Setenv("GOPPC64", goppc64)
os.Setenv("GORISCV64", goriscv64)
os.Setenv("GOROOT", goroot)
os.Setenv("GOROOT_FINAL", goroot_final)
// Set GOBIN to GOROOT/bin. The meaning of GOBIN has drifted over time
// (see https://go.dev/issue/3269, https://go.dev/cl/183058,
@ -1879,10 +1871,7 @@ func banner() {
xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot)
xprintf("Installed commands in %s\n", gorootBin)
if !xsamefile(goroot_final, goroot) {
// If the files are to be moved, don't check that gobin
// is on PATH; assume they know what they are doing.
} else if gohostos == "plan9" {
if gohostos == "plan9" {
// Check that GOROOT/bin is bound before /bin.
pid := strings.Replace(readfile("#c/pid"), " ", "", -1)
ns := fmt.Sprintf("/proc/%s/ns", pid)
@ -1907,12 +1896,6 @@ func banner() {
xprintf("*** You need to add %s to your PATH.\n", gorootBin)
}
}
if !xsamefile(goroot_final, goroot) {
xprintf("\n"+
"The binaries expect %s to be copied or moved to %s\n",
goroot, goroot_final)
}
}
// Version prints the Go version.

View file

@ -6,6 +6,7 @@ package main
import (
"go/ast"
"go/version"
"strings"
)
@ -13,7 +14,7 @@ func init() {
register(buildtagFix)
}
const buildtagGoVersionCutoff = 1_18
const buildtagGoVersionCutoff = "go1.18"
var buildtagFix = fix{
name: "buildtag",
@ -23,7 +24,7 @@ var buildtagFix = fix{
}
func buildtag(f *ast.File) bool {
if goVersion < buildtagGoVersionCutoff {
if version.Compare(*goVersion, buildtagGoVersionCutoff) < 0 {
return false
}

View file

@ -11,7 +11,7 @@ func init() {
var buildtagTests = []testCase{
{
Name: "buildtag.oldGo",
Version: 1_10,
Version: "go1.10",
In: `//go:build yes
// +build yes
@ -20,7 +20,7 @@ package main
},
{
Name: "buildtag.new",
Version: 1_99,
Version: "go1.99",
In: `//go:build yes
// +build yes

View file

@ -13,13 +13,13 @@ import (
"go/parser"
"go/scanner"
"go/token"
"go/version"
"internal/diff"
"io"
"io/fs"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
)
@ -37,10 +37,8 @@ var forceRewrites = flag.String("force", "",
var allowed, force map[string]bool
var (
doDiff = flag.Bool("diff", false, "display diffs instead of rewriting files")
goVersionStr = flag.String("go", "", "go language version for files")
goVersion int // 115 for go1.15
doDiff = flag.Bool("diff", false, "display diffs instead of rewriting files")
goVersion = flag.String("go", "", "go language version for files")
)
// enable for debugging fix failures
@ -68,24 +66,9 @@ func main() {
flag.Usage = usage
flag.Parse()
if *goVersionStr != "" {
if !strings.HasPrefix(*goVersionStr, "go") {
report(fmt.Errorf("invalid -go=%s", *goVersionStr))
os.Exit(exitCode)
}
majorStr := (*goVersionStr)[len("go"):]
minorStr := "0"
if before, after, found := strings.Cut(majorStr, "."); found {
majorStr, minorStr = before, after
}
major, err1 := strconv.Atoi(majorStr)
minor, err2 := strconv.Atoi(minorStr)
if err1 != nil || err2 != nil || major < 0 || major >= 100 || minor < 0 || minor >= 100 {
report(fmt.Errorf("invalid -go=%s", *goVersionStr))
os.Exit(exitCode)
}
goVersion = major*100 + minor
if !version.IsValid(*goVersion) {
report(fmt.Errorf("invalid -go=%s", *goVersion))
os.Exit(exitCode)
}
sort.Sort(byDate(fixes))

View file

@ -17,7 +17,7 @@ import (
type testCase struct {
Name string
Fn func(*ast.File) bool
Version int
Version string
In string
Out string
}
@ -96,7 +96,7 @@ func TestRewrite(t *testing.T) {
for _, tt := range testCases {
tt := tt
t.Run(tt.Name, func(t *testing.T) {
if tt.Version == 0 {
if tt.Version == "" {
if testing.Verbose() {
// Don't run in parallel: cmd/fix sometimes writes directly to stderr,
// and since -v prints which test is currently running we want that
@ -105,10 +105,10 @@ func TestRewrite(t *testing.T) {
t.Parallel()
}
} else {
old := goVersion
goVersion = tt.Version
old := *goVersion
*goVersion = tt.Version
defer func() {
goVersion = old
*goVersion = old
}()
}

View file

@ -5,13 +5,13 @@ go 1.23
require (
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5
golang.org/x/arch v0.7.0
golang.org/x/build v0.0.0-20240201175143-3ee44a092755
golang.org/x/build v0.0.0-20240222153247-cf4ed81bb19f
golang.org/x/mod v0.15.1-0.20240207185259-766dc5df63e3
golang.org/x/sync v0.6.0
golang.org/x/sys v0.17.0
golang.org/x/telemetry v0.0.0-20240208185543-e9b074dd3804
golang.org/x/term v0.16.0
golang.org/x/tools v0.17.1-0.20240119231502-e1555a36d006
golang.org/x/telemetry v0.0.0-20240208230135-b75ee8823808
golang.org/x/term v0.17.0
golang.org/x/tools v0.18.0
)
require (

View file

@ -10,8 +10,8 @@ github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.2.1 h1:F2aeBZrm2NDsc7vbovKrWSogd4wvfAxg0FQ89/iqOTk=
github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 h1:E/LAvt58di64hlYjx7AsNS6C/ysHWYo+2qPCZKTQhRo=
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab h1:BA4a7pe6ZTd9F8kXETBoijjFJ/ntaa//1wiH9BZu4zU=
@ -24,21 +24,21 @@ github.com/yuin/goldmark v1.6.0 h1:boZcn2GTjpsynOsC0iJHnBWa4Bi0qzfJjthwauItG68=
github.com/yuin/goldmark v1.6.0/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/build v0.0.0-20240201175143-3ee44a092755 h1:irSM9p93GT4I3+Pu/grZlkwIjrXA3GfyKwlSosVbmtU=
golang.org/x/build v0.0.0-20240201175143-3ee44a092755/go.mod h1:RHSzqFUzT4+buJlGik6WptO5NxLQiR/ewD2uz3fgWuA=
golang.org/x/build v0.0.0-20240222153247-cf4ed81bb19f h1:XQ2eu0I26WsNCKQkRehp+5mwjjChw94trD9LT8LLSq0=
golang.org/x/build v0.0.0-20240222153247-cf4ed81bb19f/go.mod h1:HTqTCkubWT8epEK9hDWWGkoOOB7LGSrU1qvWZCSwO50=
golang.org/x/mod v0.15.1-0.20240207185259-766dc5df63e3 h1:/p/VemLWiTsjHqHwME1Iu+xIu8s9fBtwBk8bU/ejA1A=
golang.org/x/mod v0.15.1-0.20240207185259-766dc5df63e3/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/telemetry v0.0.0-20240208185543-e9b074dd3804 h1:mLYQpgq+cJOnmn3pR2U9o5rzEuOVgnmw59GHPgypGeo=
golang.org/x/telemetry v0.0.0-20240208185543-e9b074dd3804/go.mod h1:KG1lNk5ZFNssSZLrpVb4sMXKMpGwGXOxSG3rnu2gZQQ=
golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
golang.org/x/telemetry v0.0.0-20240208230135-b75ee8823808 h1:+Kc94D8UVEVxJnLXp/+FMfqQARZtWHfVrcRtcG8aT3g=
golang.org/x/telemetry v0.0.0-20240208230135-b75ee8823808/go.mod h1:KG1lNk5ZFNssSZLrpVb4sMXKMpGwGXOxSG3rnu2gZQQ=
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.17.1-0.20240119231502-e1555a36d006 h1:nQlBrWcYwVcWPZJ3VI2s/bH4yjgiWJXNTELOKrnS0qk=
golang.org/x/tools v0.17.1-0.20240119231502-e1555a36d006/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
rsc.io/markdown v0.0.0-20240117044121-669d2fdf1650 h1:fuOABZYWclLVNotDsHVaFixLdtoC7+UQZJ0KSC1ocm0=
rsc.io/markdown v0.0.0-20240117044121-669d2fdf1650/go.mod h1:8xcPgWmwlZONN1D9bjxtHEjrUtSEa3fakVF8iaewYKQ=

View file

@ -2331,11 +2331,6 @@
// See src/internal/goexperiment/flags.go for currently valid values.
// Warning: This variable is provided for the development and testing
// of the Go toolchain itself. Use beyond that purpose is unsupported.
// GOROOT_FINAL
// The root of the installed Go tree, when it is
// installed in a location other than where it is built.
// File names in stack traces are rewritten from GOROOT to
// GOROOT_FINAL.
// GO_EXTLINK_ENABLED
// Whether the linker should use external linking mode
// when using -linkmode=auto with code that uses cgo.

View file

@ -90,10 +90,6 @@ func tooSlow(t *testing.T, reason string) {
// (temp) directory.
var testGOROOT string
// testGOROOT_FINAL is the GOROOT_FINAL with which the test binary is assumed to
// have been built.
var testGOROOT_FINAL = os.Getenv("GOROOT_FINAL")
var testGOCACHE string
var testGo string
@ -223,10 +219,6 @@ func TestMain(m *testing.M) {
}
testGOROOT = goEnv("GOROOT")
os.Setenv("TESTGO_GOROOT", testGOROOT)
// Ensure that GOROOT is set explicitly.
// Otherwise, if the toolchain was built with GOROOT_FINAL set but has not
// yet been moved to its final location, programs that invoke runtime.GOROOT
// may accidentally use the wrong path.
os.Setenv("GOROOT", testGOROOT)
// The whole GOROOT/pkg tree was installed using the GOHOSTOS/GOHOSTARCH

View file

@ -64,33 +64,31 @@ func ToolExeSuffix() string {
// These are general "build flags" used by build and other commands.
var (
BuildA bool // -a flag
BuildBuildmode string // -buildmode flag
BuildBuildvcs = "auto" // -buildvcs flag: "true", "false", or "auto"
BuildContext = defaultContext()
BuildMod string // -mod flag
BuildModExplicit bool // whether -mod was set explicitly
BuildModReason string // reason -mod was set, if set by default
BuildLinkshared bool // -linkshared flag
BuildMSan bool // -msan flag
BuildASan bool // -asan flag
BuildCover bool // -cover flag
BuildCoverMode string // -covermode flag
BuildCoverPkg []string // -coverpkg flag
BuildN bool // -n flag
BuildO string // -o flag
BuildP = runtime.GOMAXPROCS(0) // -p flag
BuildPGO string // -pgo flag
BuildPkgdir string // -pkgdir flag
BuildRace bool // -race flag
BuildToolexec []string // -toolexec flag
BuildToolchainName string
BuildToolchainCompiler func() string
BuildToolchainLinker func() string
BuildTrimpath bool // -trimpath flag
BuildV bool // -v flag
BuildWork bool // -work flag
BuildX bool // -x flag
BuildA bool // -a flag
BuildBuildmode string // -buildmode flag
BuildBuildvcs = "auto" // -buildvcs flag: "true", "false", or "auto"
BuildContext = defaultContext()
BuildMod string // -mod flag
BuildModExplicit bool // whether -mod was set explicitly
BuildModReason string // reason -mod was set, if set by default
BuildLinkshared bool // -linkshared flag
BuildMSan bool // -msan flag
BuildASan bool // -asan flag
BuildCover bool // -cover flag
BuildCoverMode string // -covermode flag
BuildCoverPkg []string // -coverpkg flag
BuildN bool // -n flag
BuildO string // -o flag
BuildP = runtime.GOMAXPROCS(0) // -p flag
BuildPGO string // -pgo flag
BuildPkgdir string // -pkgdir flag
BuildRace bool // -race flag
BuildToolexec []string // -toolexec flag
BuildToolchainName string
BuildTrimpath bool // -trimpath flag
BuildV bool // -v flag
BuildWork bool // -work flag
BuildX bool // -x flag
ModCacheRW bool // -modcacherw flag
ModFile string // -modfile flag
@ -181,8 +179,6 @@ func defaultContext() build.Context {
func init() {
SetGOROOT(Getenv("GOROOT"), false)
BuildToolchainCompiler = func() string { return "missing-compiler" }
BuildToolchainLinker = func() string { return "missing-linker" }
}
// SetGOROOT sets GOROOT and associated variables to the given values.
@ -203,7 +199,6 @@ func SetGOROOT(goroot string, isTestGo bool) {
GOROOTpkg = filepath.Join(goroot, "pkg")
GOROOTsrc = filepath.Join(goroot, "src")
}
GOROOT_FINAL = findGOROOT_FINAL(goroot)
installedGOOS = runtime.GOOS
installedGOARCH = runtime.GOARCH
@ -402,8 +397,6 @@ var (
GOROOTpkg string
GOROOTsrc string
GOROOT_FINAL string
GOBIN = Getenv("GOBIN")
GOMODCACHE = envOr("GOMODCACHE", gopathDir("pkg/mod"))
@ -536,16 +529,6 @@ func findGOROOT(env string) string {
return def
}
func findGOROOT_FINAL(goroot string) string {
// $GOROOT_FINAL is only for use during make.bash
// so it is not settable using go/env, so we use os.Getenv here.
def := goroot
if env := os.Getenv("GOROOT_FINAL"); env != "" {
def = filepath.Clean(env)
}
return def
}
// isSameDir reports whether dir1 and dir2 are the same directory.
func isSameDir(dir1, dir2 string) bool {
if dir1 == dir2 {

View file

@ -645,11 +645,6 @@ Special-purpose environment variables:
See src/internal/goexperiment/flags.go for currently valid values.
Warning: This variable is provided for the development and testing
of the Go toolchain itself. Use beyond that purpose is unsupported.
GOROOT_FINAL
The root of the installed Go tree, when it is
installed in a location other than where it is built.
File names in stack traces are rewritten from GOROOT to
GOROOT_FINAL.
GO_EXTLINK_ENABLED
Whether the linker should use external linking mode
when using -linkmode=auto with code that uses cgo.

View file

@ -324,7 +324,13 @@ func vendorPkg(vdir, pkg string) {
}
embeds, err := load.ResolveEmbed(bp.Dir, embedPatterns)
if err != nil {
base.Fatal(err)
format := "go: resolving embeds in %s: %v\n"
if vendorE {
fmt.Fprintf(os.Stderr, format, pkg, err)
} else {
base.Errorf(format, pkg, err)
}
return
}
for _, embed := range embeds {
embedDst := filepath.Join(dst, embed)
@ -333,23 +339,30 @@ func vendorPkg(vdir, pkg string) {
}
// Copy the file as is done by copyDir below.
r, err := os.Open(filepath.Join(src, embed))
err := func() error {
r, err := os.Open(filepath.Join(src, embed))
if err != nil {
return err
}
if err := os.MkdirAll(filepath.Dir(embedDst), 0777); err != nil {
return err
}
w, err := os.Create(embedDst)
if err != nil {
return err
}
if _, err := io.Copy(w, r); err != nil {
return err
}
r.Close()
return w.Close()
}()
if err != nil {
base.Fatal(err)
}
if err := os.MkdirAll(filepath.Dir(embedDst), 0777); err != nil {
base.Fatal(err)
}
w, err := os.Create(embedDst)
if err != nil {
base.Fatal(err)
}
if _, err := io.Copy(w, r); err != nil {
base.Fatal(err)
}
r.Close()
if err := w.Close(); err != nil {
base.Fatal(err)
if vendorE {
fmt.Fprintf(os.Stderr, "go: %v\n", err)
} else {
base.Error(err)
}
}
}
}

View file

@ -61,7 +61,7 @@ func runVerify(ctx context.Context, cmd *base.Command, args []string) {
if err != nil {
base.Fatal(err)
}
mods := mg.BuildList()[modload.MainModules.Len():]
mods := mg.BuildList()
// Use a slice of result channels, so that the output is deterministic.
errsChans := make([]<-chan []error, len(mods))
@ -94,6 +94,9 @@ func verifyMod(ctx context.Context, mod module.Version) []error {
// "go" and "toolchain" have no disk footprint; nothing to verify.
return nil
}
if modload.MainModules.Contains(mod.Path) {
return nil
}
var errs []error
zip, zipErr := modfetch.CachePath(ctx, mod, "zip")
if zipErr == nil {

View file

@ -21,6 +21,7 @@ import (
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
"cmd/go/internal/base"
@ -540,6 +541,7 @@ var (
testC bool // -c flag
testCoverPkgs []*load.Package // -coverpkg flag
testCoverProfile string // -coverprofile flag
testFailFast bool // -failfast flag
testFuzz string // -fuzz flag
testJSON bool // -json flag
testList string // -list flag
@ -589,9 +591,10 @@ var (
testHelp bool // -help option passed to test via -args
testKillTimeout = 100 * 365 * 24 * time.Hour // backup alarm; defaults to about a century if no timeout is set
testWaitDelay time.Duration // how long to wait for output to close after a test binary exits; zero means unlimited
testCacheExpire time.Time // ignore cached test results before this time
testKillTimeout = 100 * 365 * 24 * time.Hour // backup alarm; defaults to about a century if no timeout is set
testWaitDelay time.Duration // how long to wait for output to close after a test binary exits; zero means unlimited
testCacheExpire time.Time // ignore cached test results before this time
testShouldFailFast atomic.Bool // signals pending tests to fail fast
testBlockProfile, testCPUProfile, testMemProfile, testMutexProfile, testTrace string // profiling flag that limits test to one package
@ -1355,6 +1358,11 @@ func (r *runTestActor) Act(b *work.Builder, ctx context.Context, a *work.Action)
// Wait for previous test to get started and print its first json line.
select {
case <-r.prev:
// If should fail fast then release next test and exit.
if testShouldFailFast.Load() {
close(r.next)
return nil
}
case <-base.Interrupted:
// We can't wait for the previous test action to complete: we don't start
// new actions after an interrupt, so if that action wasn't already running
@ -1631,6 +1639,10 @@ func (r *runTestActor) Act(b *work.Builder, ctx context.Context, a *work.Action)
fmt.Fprintf(cmd.Stdout, "ok \t%s\t%s%s%s\n", a.Package.ImportPath, t, coveragePercentage(out), norun)
r.c.saveOutput(a)
} else {
if testFailFast {
testShouldFailFast.Store(true)
}
base.SetExitStatus(1)
if cancelSignaled {
fmt.Fprintf(cmd.Stdout, "*** Test killed with %v: ran too long (%v).\n", base.SignalTrace, testKillTimeout)

View file

@ -48,7 +48,7 @@ func init() {
cf.Int("count", 0, "")
cf.String("cpu", "", "")
cf.StringVar(&testCPUProfile, "cpuprofile", "", "")
cf.Bool("failfast", false, "")
cf.BoolVar(&testFailFast, "failfast", false, "")
cf.StringVar(&testFuzz, "fuzz", "", "")
cf.Bool("fullpath", false, "")
cf.StringVar(&testList, "list", "", "")

View file

@ -276,8 +276,6 @@ func (c buildCompiler) Set(value string) error {
return fmt.Errorf("unknown compiler %q", value)
}
cfg.BuildToolchainName = value
cfg.BuildToolchainCompiler = BuildToolchain.compiler
cfg.BuildToolchainLinker = BuildToolchain.linker
cfg.BuildContext.Compiler = value
return nil
}

View file

@ -258,9 +258,12 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID {
// when building things in GOROOT.
//
// The C compiler does not, but for packages in GOROOT we rewrite the path
// as though -trimpath were set, so that we don't invalidate the build cache
// (and especially any precompiled C archive files) when changing
// GOROOT_FINAL. (See https://go.dev/issue/50183.)
// as though -trimpath were set. This used to be so that we did not invalidate
// the build cache (and especially precompiled archive files) when changing
// GOROOT_FINAL, but we no longer ship precompiled archive files as of Go 1.20
// (https://go.dev/issue/47257) and no longer support GOROOT_FINAL
// (https://go.dev/issue/62047).
// TODO(bcmills): Figure out whether this behavior is still useful.
//
// b.WorkDir is always either trimmed or rewritten to
// the literal string "/tmp/go-build".
@ -1403,11 +1406,11 @@ func (b *Builder) printLinkerConfig(h io.Writer, p *load.Package) {
fmt.Fprintf(h, "GOEXPERIMENT=%q\n", cfg.CleanGOEXPERIMENT)
}
// The linker writes source file paths that say GOROOT_FINAL, but
// only if -trimpath is not specified (see ld() in gc.go).
gorootFinal := cfg.GOROOT_FINAL
// The linker writes source file paths that refer to GOROOT,
// but only if -trimpath is not specified (see [gctoolchain.ld] in gc.go).
gorootFinal := cfg.GOROOT
if cfg.BuildTrimpath {
gorootFinal = trimPathGoRootFinal
gorootFinal = ""
}
fmt.Fprintf(h, "GOROOT=%s\n", gorootFinal)
@ -2130,7 +2133,7 @@ func (b *Builder) ccompile(a *Action, outfile string, flags []string, file strin
file = mkAbs(p.Dir, file)
outfile = mkAbs(p.Dir, outfile)
// Elide source directory paths if -trimpath or GOROOT_FINAL is set.
// Elide source directory paths if -trimpath is set.
// This is needed for source files (e.g., a .c file in a package directory).
// TODO(golang.org/issue/36072): cgo also generates files with #line
// directives pointing to the source directory. It should not generate those

View file

@ -29,9 +29,6 @@ import (
// Tests can override this by setting $TESTGO_TOOLCHAIN_VERSION.
var ToolchainVersion = runtime.Version()
// The 'path' used for GOROOT_FINAL when -trimpath is specified
const trimPathGoRootFinal string = "$GOROOT"
// The Go toolchain.
type gcToolchain struct{}
@ -669,8 +666,11 @@ func (gcToolchain) ld(b *Builder, root *Action, targetPath, importcfg, mainpkg s
}
env := []string{}
// When -trimpath is used, GOROOT is cleared
if cfg.BuildTrimpath {
env = append(env, "GOROOT_FINAL="+trimPathGoRootFinal)
env = append(env, "GOROOT=")
} else {
env = append(env, "GOROOT="+cfg.GOROOT)
}
return b.Shell(root).run(dir, root.Package.ImportPath, env, cfg.BuildToolexec, base.Tool("link"), "-o", targetPath, "-importcfg", importcfg, ldflags, mainpkg)
}

View file

@ -97,7 +97,7 @@ func main() {
flag.Usage = base.Usage
flag.Parse()
counter.CountFlags("cmd/go:flag-", *flag.CommandLine)
counter.CountFlags("cmd/go/flag:", *flag.CommandLine)
args := flag.Args()
if len(args) < 1 {
@ -153,7 +153,7 @@ func main() {
cmd, used := lookupCmd(args)
cfg.CmdName = strings.Join(args[:used], " ")
counter.Inc("cmd/go:subcommand-" + strings.ReplaceAll(cfg.CmdName, " ", "-"))
counter.Inc("cmd/go/subcommand:" + strings.ReplaceAll(cfg.CmdName, " ", "-"))
if len(cmd.Commands) > 0 {
if used >= len(args) {
help.PrintUsage(os.Stderr, cmd)
@ -241,7 +241,7 @@ func invoke(cmd *base.Command, args []string) {
} else {
base.SetFromGOFLAGS(&cmd.Flag)
cmd.Flag.Parse(args[1:])
counter.CountFlags("cmd/go/"+cmd.Name()+":flag-", cmd.Flag)
counter.CountFlags("cmd/go/flag:"+cmd.Name()+"-", cmd.Flag)
args = cmd.Flag.Args()
}

View file

@ -223,7 +223,6 @@ func scriptEnv(srv *vcstest.Server, srvCertFile string) ([]string, error) {
"GOPROXY=" + proxyURL,
"GOPRIVATE=",
"GOROOT=" + testGOROOT,
"GOROOT_FINAL=" + testGOROOT_FINAL, // causes spurious rebuilds and breaks the "stale" built-in if not propagated
"GOTRACEBACK=system",
"TESTGONETWORK=panic", // allow only local connections by default; the [net] condition resets this
"TESTGO_GOROOT=" + testGOROOT,

View file

@ -51,7 +51,6 @@ func scriptConditions() map[string]script.Cond {
add("GOEXPERIMENT", script.PrefixCondition("GOEXPERIMENT <suffix> is enabled", hasGoexperiment))
add("go-builder", script.BoolCondition("GO_BUILDER_NAME is non-empty", testenv.Builder() != ""))
add("link", lazyBool("testenv.HasLink()", testenv.HasLink))
add("mismatched-goroot", script.Condition("test's GOROOT_FINAL does not match the real GOROOT", isMismatchedGoroot))
add("msan", sysCondition("-msan", platform.MSanSupported, true))
add("mustlinkext", script.Condition("platform always requires external linking", mustLinkExt))
add("net", script.PrefixCondition("can connect to external network host <suffix>", hasNet))
@ -85,14 +84,6 @@ func ccIs(s *script.State, want string) (bool, error) {
return cfg.DefaultCC(GOOS, GOARCH) == want, nil
}
func isMismatchedGoroot(s *script.State) (bool, error) {
gorootFinal, _ := s.LookupEnv("GOROOT_FINAL")
if gorootFinal == "" {
gorootFinal, _ = s.LookupEnv("GOROOT")
}
return gorootFinal != testGOROOT, nil
}
func sysCondition(flag string, f func(goos, goarch string) bool, needsCgo bool) script.Cond {
return script.Condition(
"GOOS/GOARCH supports "+flag,

View file

@ -120,7 +120,6 @@ Scripts also have access to other environment variables, including:
GOPATH=$WORK/gopath
GOPROXY=<local module proxy serving from cmd/go/testdata/mod>
GOROOT=<actual GOROOT>
GOROOT_FINAL=<actual GOROOT_FINAL>
TESTGO_GOROOT=<GOROOT used to build cmd/go, for use in tests that may change GOROOT>
HOME=/no-home
PATH=<actual PATH>

View file

@ -35,7 +35,6 @@ Scripts also have access to other environment variables, including:
GOPATH=$WORK/gopath
GOPROXY=<local module proxy serving from cmd/go/testdata/mod>
GOROOT=<actual GOROOT>
GOROOT_FINAL=<actual GOROOT_FINAL>
TESTGO_GOROOT=<GOROOT used to build cmd/go, for use in tests that may change GOROOT>
HOME=/no-home
PATH=<actual PATH>
@ -402,8 +401,6 @@ The available conditions are:
GO_BUILDER_NAME is non-empty
[link]
testenv.HasLink()
[mismatched-goroot]
test's GOROOT_FINAL does not match the real GOROOT
[msan]
GOOS/GOARCH supports -msan
[mustlinkext]

View file

@ -1,46 +0,0 @@
# Regression test for https://go.dev/issue/48319:
# cgo builds should not include debug information from a stale GOROOT_FINAL.
[short] skip
[!cgo] skip
# This test is sensitive to cache invalidation,
# so use a separate build cache that we can control.
env GOCACHE=$WORK/gocache
mkdir $GOCACHE
# Build a binary using a specific value of GOROOT_FINAL.
env GOROOT_FINAL=$WORK${/}goroot1
go build -o main.exe
mv main.exe main1.exe
# Now clean the cache and build using a different GOROOT_FINAL.
# The resulting binaries should differ in their debug metadata.
go clean -cache
env GOROOT_FINAL=$WORK${/}goroot2
go build -o main.exe
mv main.exe main2.exe
! cmp -q main2.exe main1.exe
# Set GOROOT_FINAL back to the first value.
# If the build is properly reproducible, the two binaries should match.
env GOROOT_FINAL=$WORK${/}goroot1
go build -o main.exe
cmp -q main.exe main1.exe
-- go.mod --
module main
go 1.18
-- main.go --
package main
import "C"
import "runtime"
var _ C.int
func main() {
println(runtime.GOROOT())
}

View file

@ -2,6 +2,13 @@
[short] skip
[!cgo] skip '-buildmode=plugin requires external linking'
# This test has problems when run on the LUCI darwin longtest builder,
# which uses a more contemporary Xcode version that is unfriendly to
# reproducible builds (see issue #64947 for the gory details). Note
# that individual developers running "go test cmd/go" on Darwin may
# still run into failures depending on their Xcode version.
[GOOS:darwin] [go-builder] skip
go build -trimpath -buildvcs=false -buildmode=plugin -o a.so main.go
go build -trimpath -buildvcs=false -buildmode=plugin -o b.so main.go
cmp -q a.so b.so

View file

@ -1,8 +1,8 @@
[short] skip
# If GOROOT_FINAL is set, 'go build -trimpath' bakes that into the resulting
# binary instead of GOROOT. Explicitly unset it here.
env GOROOT_FINAL=
# If GOROOT is set, 'go build -trimpath' bakes that into the resulting
# binary. Explicitly unset it here.
env GOROOT=
# Set up two identical directories that can be used as GOPATH.
env GO111MODULE=on
@ -21,14 +21,13 @@ cd $WORK/a/src/paths
go build -o $WORK/paths-dbg.exe .
exec $WORK/paths-dbg.exe $WORK/paths-dbg.exe
stdout 'binary contains module root: true'
stdout 'binary contains GOROOT: true'
stdout 'binary contains an empty GOROOT'
# A binary built with -trimpath should not contain the current workspace
# or GOROOT.
# A binary built with -trimpath should not contain the current workspace.
go build -trimpath -o $WORK/paths-a.exe .
exec $WORK/paths-a.exe $WORK/paths-a.exe
stdout 'binary contains module root: false'
stdout 'binary contains GOROOT: false'
stdout 'binary contains an empty GOROOT'
# A binary from an external module built with -trimpath should not contain
# the current workspace or GOROOT.
@ -36,7 +35,7 @@ go get rsc.io/fortune
go install -trimpath rsc.io/fortune
exec $WORK/paths-a.exe $GOPATH/bin/fortune$GOEXE
stdout 'binary contains module root: false'
stdout 'binary contains GOROOT: false'
stdout 'binary contains an empty GOROOT'
go mod edit -droprequire rsc.io/fortune
# Two binaries built from identical packages in different directories
@ -53,14 +52,13 @@ cd $WORK/a/src/paths
go build -overlay overlay.json -o $WORK/paths-dbg.exe ./overlaydir
exec $WORK/paths-dbg.exe $WORK/paths-dbg.exe
stdout 'binary contains module root: true'
stdout 'binary contains GOROOT: true'
stdout 'binary contains an empty GOROOT'
# A binary built with -trimpath should not contain the current workspace
# or GOROOT.
# A binary built with -trimpath should not contain the current workspace.
go build -overlay overlay.json -trimpath -o $WORK/paths-a.exe ./overlaydir
exec $WORK/paths-a.exe $WORK/paths-a.exe
stdout 'binary contains module root: false'
stdout 'binary contains GOROOT: false'
stdout 'binary contains an empty GOROOT'
# Two binaries built from identical packages in different directories
# should be identical.
@ -77,13 +75,13 @@ env GOPATH=$WORK/a
go build -o paths-dbg.exe paths
exec ./paths-dbg.exe paths-dbg.exe
stdout 'binary contains GOPATH: true'
stdout 'binary contains GOROOT: true'
stdout 'binary contains an empty GOROOT'
# A binary built with -trimpath should not contain GOPATH or GOROOT.
# A binary built with -trimpath should not contain GOPATH.
go build -trimpath -o paths-a.exe paths
exec ./paths-a.exe paths-a.exe
stdout 'binary contains GOPATH: false'
stdout 'binary contains GOROOT: false'
stdout 'binary contains an empty GOROOT'
# Two binaries built from identical packages in different GOPATH roots
# should be identical.
@ -103,13 +101,14 @@ env GOPATH=$WORK/a
go build -compiler=gccgo -o paths-dbg.exe paths
exec ./paths-dbg.exe paths-dbg.exe
stdout 'binary contains GOPATH: true'
stdout 'binary contains GOROOT: false' # gccgo doesn't load std from GOROOT.
stdout 'binary contains an empty GOROOT'
# gccgo doesn't load std from GOROOT.
# A binary built with gccgo with -trimpath should not contain GOPATH or GOROOT.
go build -compiler=gccgo -trimpath -o paths-a.exe paths
exec ./paths-a.exe paths-a.exe
stdout 'binary contains GOPATH: false'
stdout 'binary contains GOROOT: false'
stdout 'binary contains an empty GOROOT'
# Two binaries built from identical packages in different directories
# should be identical.
@ -152,6 +151,10 @@ func main() {
}
func check(data []byte, desc, dir string) {
if dir == "" {
fmt.Printf("binary contains an empty %s\n", desc)
return
}
containsDir := bytes.Contains(data, []byte(dir))
containsSlashDir := bytes.Contains(data, []byte(filepath.ToSlash(dir)))
fmt.Printf("binary contains %s: %v\n", desc, containsDir || containsSlashDir)

View file

@ -4,11 +4,6 @@
# if GOROOT was not set explicitly in the environment.
# It should instead return the empty string, since we know that we don't
# have a valid path to return.
#
# TODO(#51483): when runtime.GOROOT() returns the empty string,
# go/build should default to 'go env GOROOT' instead.
env GOROOT_FINAL=
[trimpath] env GOROOT=
[trimpath] ! go env GOROOT
@ -17,7 +12,7 @@ env GOROOT_FINAL=
[short] stop
# With GOROOT still set but GOROOT_FINAL unset, 'go build' and 'go test -c'
# With GOROOT still set, 'go build' and 'go test -c'
# should cause runtime.GOROOT() to report either the correct GOROOT
# (without -trimpath) or no GOROOT at all (with -trimpath).
@ -52,7 +47,6 @@ stderr 'cannot find package "runtime" in any of:\n\t\(\$GOROOT not set\)\n\t'$WO
# code).
[trimpath] stop
[mismatched-goroot] stop
! go run -trimpath .
stdout '^GOROOT $'

View file

@ -1,5 +1,5 @@
# Regression test for https://go.dev/issue/47215 and https://go.dev/issue/50183:
# A mismatched $GOROOT_FINAL or missing $CC caused the C dependencies of the net
# A missing $CC caused the C dependencies of the net
# package to appear stale, and it could not be rebuilt due to a missing $CC.
[!cgo] skip
@ -16,14 +16,6 @@
go build -x runtime/cgo
[!short] stderr '[/\\]cgo'$GOEXE'["]? .* -importpath runtime/cgo'
# https://go.dev/issue/50183: a mismatched GOROOT_FINAL caused net to be stale.
env oldGOROOT_FINAL=$GOROOT_FINAL
env GOROOT_FINAL=$WORK${/}goroot
go build -x runtime/cgo
! stderr '[/\\]cgo'$GOEXE'["]? .* -importpath runtime/cgo'
env GOROOT_FINAL=$oldGOROOT_FINAL
# https://go.dev/issue/47215: a missing $(go env CC) caused the precompiled net
# to be stale. But as of https://go.dev/cl/452457 the precompiled libraries are
# no longer installed anyway! Since we're requiring a C compiler in order to

View file

@ -3,16 +3,9 @@
mkdir $WORK/new/bin
# In this test, we are specifically checking the logic for deriving
# the value of GOROOT from runtime.GOROOT.
# GOROOT_FINAL changes the default behavior of runtime.GOROOT,
# and will thus cause the test to fail if it is set when our
# new cmd/go is built.
env GOROOT_FINAL=
# $GOROOT/bin/go is whatever the user has already installed
# (using make.bash or similar). We can't make assumptions about what
# options it may have been built with, such as -trimpath or GOROOT_FINAL.
# options it may have been built with, such as -trimpath or not.
# Instead, we build a fresh copy of the binary with known settings.
go build -o $WORK/new/bin/go$GOEXE cmd/go &
go build -trimpath -o $WORK/bin/check$GOEXE check.go &

View file

@ -14,13 +14,10 @@ mkdir $WORK/new/bin/${GOOS}_${GOARCH}
# In this test, we are specifically checking the logic for deriving
# the value of GOROOT from os.Executable when runtime.GOROOT is
# trimmed away.
# GOROOT_FINAL changes the default behavior of runtime.GOROOT,
# so we explicitly clear it to remove it as a confounding variable.
env GOROOT_FINAL=
# $GOROOT/bin/go is whatever the user has already installed
# (using make.bash or similar). We can't make assumptions about what
# options it may have been built with, such as -trimpath or GOROOT_FINAL.
# options it may have been built with, such as -trimpath or not.
# Instead, we build a fresh copy of the binary with known settings.
go build -trimpath -o $WORK/new/bin/go$GOEXE cmd/go &
go build -trimpath -o $WORK/bin/check$GOEXE check.go &

View file

@ -6,11 +6,15 @@ cmp vendor/example.com/a/subdir/test/xtest/embed.txt a/subdir/test/xtest/embed.t
cd broken_no_matching_files
! go mod vendor
stderr 'go: pattern foo.txt: no matching files found'
stderr '^go: resolving embeds in example.com/brokendep: pattern foo.txt: no matching files found$'
go mod vendor -e
stderr '^go: resolving embeds in example.com/brokendep: pattern foo.txt: no matching files found$'
cd ../broken_bad_pattern
! go mod vendor
stderr 'go: pattern ../foo.txt: invalid pattern syntax'
stderr '^go: resolving embeds in example.com/brokendep: pattern ../foo.txt: invalid pattern syntax$'
go mod vendor -e
stderr '^go: resolving embeds in example.com/brokendep: pattern ../foo.txt: invalid pattern syntax$'
cd ../embed_go122
go mod vendor

View file

@ -0,0 +1,24 @@
# Regression test for Issue #62663: we would filter out the toolchain and
# main modules from the build list incorrectly, leading to the workspace
# modules being checked for correct sums. Specifically this would happen when
# the module name sorted after the virtual 'go' version module name because
# it could not get chopped off when we removed the MainModules.Len() modules
# at the beginning of the build list and we would remove the go module instead.
go mod verify
-- go.work --
go 1.21
use (
./a
./b
)
-- a/go.mod --
module hexample.com/a // important for test that module name sorts after 'go'
go 1.21
-- b/go.mod --
module hexample.com/b // important for test that module name sorts after 'go'
go 1.21

View file

@ -48,6 +48,15 @@ stdout -count=1 'FAIL - '
! go test ./failfast_test.go -run='TestFatal[CD]' -failfast=false
stdout -count=2 'FAIL - '
# cross package failfast
! go test -p 1 -failfast ./a ./b ./c
stdout -count=1 'FAIL - '
stdout -count=1 'FAIL - TestFailingPkgA'
-- go.mod --
module m
go 1.21.0
-- failfast_test.go --
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
@ -111,3 +120,27 @@ func TestFatalC(t *testing.T) {
func TestFatalD(t *testing.T) {
t.Fatalf("FAIL - %s", t.Name())
}
-- a/a_test.go --
package a
import "testing"
func TestFailingPkgA(t *testing.T) {
t.Errorf("FAIL - %s", t.Name())
}
-- b/b_test.go --
package b
import "testing"
func TestFailingPkgB(t *testing.T) {
t.Errorf("FAIL - %s", t.Name())
}
-- c/c_test.go --
package c
import "testing"
func TestFailingPkgC(t *testing.T) {
t.Errorf("FAIL - %s", t.Name())
}

View file

@ -555,7 +555,7 @@ func backupFile(filename string, data []byte, perm fs.FileMode) (string, error)
if err == nil {
break
}
if err != nil && !os.IsExist(err) {
if !os.IsExist(err) {
return "", err
}
}

Some files were not shown because too many files have changed in this diff Show more